5 use Consolidation\AnnotatedCommand\AnnotationData;
6 use Drush\Log\DrushLog;
7 use Symfony\Component\HttpFoundation\Request;
8 use Symfony\Component\HttpFoundation\Response;
9 use Drupal\Core\DrupalKernel;
11 use Drush\Drupal\DrushServiceModifier;
13 use Drush\Log\LogLevel;
15 class DrupalBoot8 extends DrupalBoot implements AutoloaderAwareInterface
17 use AutoloaderAwareTrait;
20 * @var \Drupal\Core\DrupalKernelInterface
25 * @var \Symfony\Component\HttpFoundation\Request
30 * @return \Symfony\Component\HttpFoundation\Request
32 public function getRequest()
34 return $this->request;
38 * @param \Symfony\Component\HttpFoundation\Request $request
40 public function setRequest($request)
42 $this->request = $request;
46 * @return \Drupal\Core\DrupalKernelInterface
48 public function getKernel()
53 public function validRoot($path)
55 if (!empty($path) && is_dir($path) && file_exists($path . '/autoload.php')) {
56 // Additional check for the presence of core/composer.json to
57 // grant it is not a Drupal 7 site with a base folder named "core".
58 $candidate = 'core/includes/common.inc';
59 if (file_exists($path . '/' . $candidate) && file_exists($path . '/core/core.services.yml')) {
60 if (file_exists($path . '/core/misc/drupal.js') || file_exists($path . '/core/assets/js/drupal.js')) {
67 public function getVersion($drupal_root)
69 // Are the class constants available?
70 if (!$this->hasAutoloader()) {
71 throw new \Exception('Cannot access Drupal 8 class constants - Drupal autoloader not loaded yet.');
73 // Drush depends on bootstrap being loaded at this point.
74 require_once $drupal_root .'/core/includes/bootstrap.inc';
75 if (defined('\Drupal::VERSION')) {
76 return \Drupal::VERSION;
80 public function confPath($require_settings = true, $reset = false)
83 if (\Drupal::hasService('kernel')) {
84 $site_path = \Drupal::service('kernel')->getSitePath();
86 if (!isset($site_path) || empty($site_path)) {
87 $site_path = DrupalKernel::findSitePath($this->getRequest(), $require_settings);
92 public function addLogger()
94 // Provide a logger which sends
95 // output to drush_log(). This should catch every message logged through every
97 $container = \Drupal::getContainer();
98 $parser = $container->get('logger.log_message_parser');
100 $drushLogger = Drush::logger();
101 $logger = new DrushLog($parser, $drushLogger);
102 $container->get('logger.factory')->addLogger($logger);
105 public function bootstrapDrupalCore($drupal_root)
107 $core = DRUPAL_ROOT . '/core';
112 public function bootstrapDrupalSiteValidate()
114 parent::bootstrapDrupalSiteValidate();
117 $uri = rtrim($this->uri, '/') . '/';
118 $parsed_url = parse_url($uri);
120 // Account for users who omit the http:// prefix.
121 if (empty($parsed_url['scheme'])) {
122 $this->uri = 'http://' . $this->uri;
123 $parsed_url = parse_url($this->uri);
127 'SCRIPT_FILENAME' => getcwd() . '/index.php',
128 'SCRIPT_NAME' => isset($parsed_url['path']) ? $parsed_url['path'] . 'index.php' : '/index.php',
130 $request = Request::create($this->uri, 'GET', [], [], [], $server);
131 $this->setRequest($request);
132 $confPath = drush_bootstrap_value('confPath', $this->confPath(true, true));
133 drush_bootstrap_value('site', $request->getHttpHost());
137 public function bootstrapDrupalConfigurationValidate()
139 $conf_file = $this->confPath() . '/settings.php';
140 if (!file_exists($conf_file)) {
141 $msg = dt("Could not find a Drupal settings.php file at !file.", ['!file' => $conf_file]);
142 $this->logger->debug($msg);
143 // Cant do this because site:install deliberately bootstraps to configure without a settings.php file.
144 // return drush_set_error($msg);
149 public function bootstrapDrupalDatabaseValidate()
151 return parent::bootstrapDrupalDatabaseValidate() && $this->bootstrapDrupalDatabaseHasTable('key_value');
154 public function bootstrapDrupalDatabase()
156 // D8 omits this bootstrap level as nothing special needs to be done.
157 parent::bootstrapDrupalDatabase();
160 public function bootstrapDrupalConfiguration(AnnotationData $annotationData = null)
162 // Default to the standard kernel.
163 $kernel = Kernels::DRUPAL;
164 if (!empty($annotationData)) {
165 $kernel = $annotationData->get('kernel', Kernels::DRUPAL);
167 $classloader = $this->autoloader();
168 $request = $this->getRequest();
169 $kernel_factory = Kernels::getKernelFactory($kernel);
170 $allow_dumping = $kernel !== Kernels::UPDATE;
171 /** @var \Drupal\Core\DrupalKernelInterface kernel */
172 $this->kernel = $kernel_factory($request, $classloader, 'prod', $allow_dumping);
173 // Include Drush services in the container.
174 // @see Drush\Drupal\DrupalKernel::addServiceModifier()
175 $this->kernel->addServiceModifier(new DrushServiceModifier());
177 // Unset drupal error handler and restore Drush's one.
178 restore_error_handler();
180 // Disable automated cron if the module is enabled.
181 $GLOBALS['config']['automated_cron.settings']['interval'] = 0;
183 parent::bootstrapDrupalConfiguration();
186 public function bootstrapDrupalFull()
188 $this->logger->debug(dt('Start bootstrap of the Drupal Kernel.'));
189 $this->kernel->boot();
190 $this->kernel->prepareLegacyRequest($this->getRequest());
191 $this->logger->debug(dt('Finished bootstrap of the Drupal Kernel.'));
193 parent::bootstrapDrupalFull();
196 // Get a list of the modules to ignore
197 $ignored_modules = drush_get_option_list('ignored-modules', []);
199 $application = Drush::getApplication();
200 $runner = Drush::runner();
202 // We have to get the service command list from the container, because
203 // it is constructed in an indirect way during the container initialization.
204 // The upshot is that the list of console commands is not available
205 // until after $kernel->boot() is called.
206 $container = \Drupal::getContainer();
208 // Set the command info alterers.
209 if ($container->has(DrushServiceModifier::DRUSH_COMMAND_INFO_ALTERER_SERVICES)) {
210 $serviceCommandInfoAltererlist = $container->get(DrushServiceModifier::DRUSH_COMMAND_INFO_ALTERER_SERVICES);
211 $commandFactory = Drush::commandFactory();
212 foreach ($serviceCommandInfoAltererlist->getCommandList() as $altererHandler) {
213 $commandFactory->addCommandInfoAlterer($altererHandler);
214 $this->logger->debug(dt('Commands are potentially altered in !class.', ['!class' => get_class($altererHandler)]));
218 $serviceCommandlist = $container->get(DrushServiceModifier::DRUSH_CONSOLE_SERVICES);
219 if ($container->has(DrushServiceModifier::DRUSH_CONSOLE_SERVICES)) {
220 foreach ($serviceCommandlist->getCommandList() as $command) {
221 if (!$this->commandIgnored($command, $ignored_modules)) {
222 $this->inflect($command);
223 $this->logger->log(LogLevel::DEBUG_NOTIFY, dt('Add a command: !name', ['!name' => $command->getName()]));
224 $application->add($command);
228 // Do the same thing with the annotation commands.
229 if ($container->has(DrushServiceModifier::DRUSH_COMMAND_SERVICES)) {
230 $serviceCommandlist = $container->get(DrushServiceModifier::DRUSH_COMMAND_SERVICES);
231 foreach ($serviceCommandlist->getCommandList() as $commandHandler) {
232 if (!$this->commandIgnored($commandHandler, $ignored_modules)) {
233 $this->inflect($commandHandler);
234 $this->logger->log(LogLevel::DEBUG_NOTIFY, dt('Add a commandfile class: !name', ['!name' => get_class($commandHandler)]));
235 $runner->registerCommandClass($application, $commandHandler);
241 public function commandIgnored($command, $ignored_modules)
243 if (empty($ignored_modules)) {
246 $ignored_regex = '#\\\\(' . implode('|', $ignored_modules) . ')\\\\#';
247 $class = new \ReflectionClass($command);
248 $commandNamespace = $class->getNamespaceName();
249 return preg_match($ignored_regex, $commandNamespace);
255 public function terminate()
260 $response = Response::create('');
261 $this->kernel->terminate($this->getRequest(), $response);