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();
115 // Account for users who omit the http:// prefix.
116 if (!parse_url($this->uri, PHP_URL_SCHEME)) {
117 $this->uri = 'http://' . $this->uri;
119 $request = Request::create($this->uri, 'GET', [], [], [], ['SCRIPT_NAME' => '/index.php']);
120 $this->setRequest($request);
121 $confPath = drush_bootstrap_value('confPath', $this->confPath(true, true));
122 drush_bootstrap_value('site', $request->getHttpHost());
126 public function bootstrapDrupalConfigurationValidate()
128 $conf_file = $this->confPath() . '/settings.php';
129 if (!file_exists($conf_file)) {
130 $msg = dt("Could not find a Drupal settings.php file at !file.", ['!file' => $conf_file]);
131 $this->logger->debug($msg);
132 // Cant do this because site:install deliberately bootstraps to configure without a settings.php file.
133 // return drush_set_error($msg);
138 public function bootstrapDrupalDatabaseValidate()
140 return parent::bootstrapDrupalDatabaseValidate() && $this->bootstrapDrupalDatabaseHasTable('key_value');
143 public function bootstrapDrupalDatabase()
145 // D8 omits this bootstrap level as nothing special needs to be done.
146 parent::bootstrapDrupalDatabase();
149 public function bootstrapDrupalConfiguration(AnnotationData $annotationData = null)
151 // Default to the standard kernel.
152 $kernel = Kernels::DRUPAL;
153 if (!empty($annotationData)) {
154 $kernel = $annotationData->get('kernel', Kernels::DRUPAL);
156 $classloader = $this->autoloader();
157 $request = $this->getRequest();
158 $kernel_factory = Kernels::getKernelFactory($kernel);
159 /** @var \Drupal\Core\DrupalKernelInterface kernel */
160 $this->kernel = $kernel_factory($request, $classloader, 'prod');
161 // Include Drush services in the container.
162 // @see Drush\Drupal\DrupalKernel::addServiceModifier()
163 $this->kernel->addServiceModifier(new DrushServiceModifier());
165 // Unset drupal error handler and restore Drush's one.
166 restore_error_handler();
168 // Disable automated cron if the module is enabled.
169 $GLOBALS['config']['automated_cron.settings']['interval'] = 0;
171 parent::bootstrapDrupalConfiguration();
174 public function bootstrapDrupalFull()
176 $this->logger->debug(dt('Start bootstrap of the Drupal Kernel.'));
177 $this->kernel->boot();
178 $this->kernel->prepareLegacyRequest($this->getRequest());
179 $this->logger->debug(dt('Finished bootstrap of the Drupal Kernel.'));
181 parent::bootstrapDrupalFull();
184 // Get a list of the modules to ignore
185 $ignored_modules = drush_get_option_list('ignored-modules', []);
187 $application = Drush::getApplication();
188 $runner = Drush::runner();
190 // We have to get the service command list from the container, because
191 // it is constructed in an indirect way during the container initialization.
192 // The upshot is that the list of console commands is not available
193 // until after $kernel->boot() is called.
194 $container = \Drupal::getContainer();
196 // Set the command info alterers.
197 if ($container->has(DrushServiceModifier::DRUSH_COMMAND_INFO_ALTERER_SERVICES)) {
198 $serviceCommandInfoAltererlist = $container->get(DrushServiceModifier::DRUSH_COMMAND_INFO_ALTERER_SERVICES);
199 $commandFactory = Drush::commandFactory();
200 foreach ($serviceCommandInfoAltererlist->getCommandList() as $altererHandler) {
201 $commandFactory->addCommandInfoAlterer($altererHandler);
202 $this->logger->debug(dt('Commands are potentially altered in !class.', ['!class' => get_class($altererHandler)]));
206 $serviceCommandlist = $container->get(DrushServiceModifier::DRUSH_CONSOLE_SERVICES);
207 if ($container->has(DrushServiceModifier::DRUSH_CONSOLE_SERVICES)) {
208 foreach ($serviceCommandlist->getCommandList() as $command) {
209 if (!$this->commandIgnored($command, $ignored_modules)) {
210 $this->inflect($command);
211 $this->logger->log(LogLevel::DEBUG_NOTIFY, dt('Add a command: !name', ['!name' => $command->getName()]));
212 $application->add($command);
216 // Do the same thing with the annotation commands.
217 if ($container->has(DrushServiceModifier::DRUSH_COMMAND_SERVICES)) {
218 $serviceCommandlist = $container->get(DrushServiceModifier::DRUSH_COMMAND_SERVICES);
219 foreach ($serviceCommandlist->getCommandList() as $commandHandler) {
220 if (!$this->commandIgnored($commandHandler, $ignored_modules)) {
221 $this->inflect($commandHandler);
222 $this->logger->log(LogLevel::DEBUG_NOTIFY, dt('Add a commandfile class: !name', ['!name' => get_class($commandHandler)]));
223 $runner->registerCommandClass($application, $commandHandler);
229 public function commandIgnored($command, $ignored_modules)
231 if (empty($ignored_modules)) {
234 $ignored_regex = '#\\\\(' . implode('|', $ignored_modules) . ')\\\\#';
235 $class = new \ReflectionClass($command);
236 $commandNamespace = $class->getNamespaceName();
237 return preg_match($ignored_regex, $commandNamespace);
243 public function terminate()
248 $response = Response::create('');
249 $this->kernel->terminate($this->getRequest(), $response);