/
DrupalBoot8.php
298 lines (260 loc) · 11.2 KB
/
DrupalBoot8.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
<?php
namespace Drush\Boot;
use Consolidation\AnnotatedCommand\AnnotationData;
use Drupal\Core\Database\Database;
use Drupal\Core\DrupalKernel;
use Drush\Drupal\DrushServiceModifier;
use Drush\Drush;
use Drush\Log\DrushLog;
use Drush\Log\LogLevel;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Webmozart\PathUtil\Path;
use Psr\Log\LoggerInterface;
class DrupalBoot8 extends DrupalBoot implements AutoloaderAwareInterface
{
use AutoloaderAwareTrait;
/**
* @var LoggerInterface
*/
protected $drupalLoggerAdapter;
/**
* @var \Drupal\Core\DrupalKernelInterface
*/
protected $kernel;
/**
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* @return \Symfony\Component\HttpFoundation\Request
*/
public function getRequest()
{
return $this->request;
}
/**
* @param \Symfony\Component\HttpFoundation\Request $request
*/
public function setRequest($request)
{
$this->request = $request;
}
/**
* @return \Drupal\Core\DrupalKernelInterface
*/
public function getKernel()
{
return $this->kernel;
}
/**
* Sometimes (e.g. in the integration tests), the DrupalBoot
* object will be cached, and re-injected into a fresh set
* of preflight / bootstrap objects. When this happens, the
* new Drush logger will be injected into the boot object. If
* this happens after we have created the Drupal logger adapter
* (i.e., after bootstrapping Drupal), then we also need to
* update the logger reference in that adapter.
*/
public function setLogger(LoggerInterface $logger)
{
if ($this->drupalLoggerAdapter) {
$this->drupalLoggerAdapter->setLogger($logger);
}
parent::setLogger($logger);
}
public function validRoot($path)
{
if (!empty($path) && is_dir($path) && file_exists($path . '/autoload.php')) {
// Additional check for the presence of core/composer.json to
// grant it is not a Drupal 7 site with a base folder named "core".
$candidate = 'core/includes/common.inc';
if (file_exists($path . '/' . $candidate) && file_exists($path . '/core/core.services.yml')) {
if (file_exists($path . '/core/misc/drupal.js') || file_exists($path . '/core/assets/js/drupal.js')) {
return $candidate;
}
}
}
}
public function getVersion($drupal_root)
{
// Are the class constants available?
if (!$this->hasAutoloader()) {
throw new \Exception('Cannot access Drupal 8 class constants - Drupal autoloader not loaded yet.');
}
// Drush depends on bootstrap being loaded at this point.
require_once $drupal_root .'/core/includes/bootstrap.inc';
if (defined('\Drupal::VERSION')) {
return \Drupal::VERSION;
}
}
public function confPath($require_settings = true, $reset = false)
{
if (\Drupal::hasService('kernel')) {
$site_path = \Drupal::service('kernel')->getSitePath();
}
if (!isset($site_path) || empty($site_path)) {
$site_path = DrupalKernel::findSitePath($this->getRequest(), $require_settings);
}
return $site_path;
}
public function addLogger()
{
// Provide a logger which sends
// output to drush_log(). This should catch every message logged through every
// channel.
$container = \Drupal::getContainer();
$parser = $container->get('logger.log_message_parser');
$drushLogger = Drush::logger();
$this->drupalLoggerAdapter = new DrushLog($parser, $drushLogger);
$container->get('logger.factory')->addLogger($this->drupalLoggerAdapter);
}
public function bootstrapDrupalCore(BootstrapManager $manager, $drupal_root)
{
return Path::join($drupal_root, 'core');
}
public function bootstrapDrupalSiteValidate(BootstrapManager $manager)
{
parent::bootstrapDrupalSiteValidate($manager);
// Normalize URI.
$uri = rtrim($this->uri, '/') . '/';
$parsed_url = parse_url($uri);
// Account for users who omit the http:// prefix.
if (empty($parsed_url['scheme'])) {
$this->uri = 'http://' . $this->uri;
$parsed_url = parse_url('http://' . $uri);
}
$server = [
'SCRIPT_FILENAME' => getcwd() . '/index.php',
'SCRIPT_NAME' => isset($parsed_url['path']) ? $parsed_url['path'] . 'index.php' : '/index.php',
];
$request = Request::create($this->uri, 'GET', [], [], [], $server);
$this->setRequest($request);
return true;
}
/**
* Called by bootstrapDrupalSite to do the main work
* of the drush drupal site bootstrap.
*/
public function bootstrapDoDrupalSite(BootstrapManager $manager)
{
$this->logger->log(LogLevel::BOOTSTRAP, dt("Initialized Drupal site !site at !site_root", ['!site' => $this->getRequest()->getHttpHost(), '!site_root' => $this->confPath()]));
}
public function bootstrapDrupalConfigurationValidate(BootstrapManager $manager)
{
$conf_file = $this->confPath() . '/settings.php';
if (!file_exists($conf_file)) {
$msg = dt("Could not find a Drupal settings.php file at !file.", ['!file' => $conf_file]);
$this->logger->debug($msg);
// Cant do this because site:install deliberately bootstraps to configure without a settings.php file.
// return drush_set_error($msg);
}
return true;
}
public function bootstrapDrupalDatabaseValidate(BootstrapManager $manager)
{
// Drupal requires PDO, and Drush requires php 5.6+ which ships with PDO
// but PHP may be compiled with --disable-pdo.
if (!class_exists('\PDO')) {
$this->logger->log(LogLevel::BOOTSTRAP, dt('PDO support is required.'));
return false;
}
try {
// @todo Log queries in addition to logging failure messages?
$connection = Database::getConnection();
$connection->query('SELECT 1;');
} catch (\Exception $e) {
$this->logger->log(LogLevel::BOOTSTRAP, 'Unable to connect to database. More information may be available by running `drush status`. This may occur when Drush is trying to bootstrap a site that has not been installed or does not have a configured database. In this case you can select another site with a working database setup by specifying the URI to use with the --uri parameter on the command line. See `drush topic docs-aliases` for details.');
return false;
}
if (!$connection->schema()->tableExists('key_value')) {
$this->logger->log(LogLevel::BOOTSTRAP, 'key_value table not found. Database may be empty.');
return false;
}
return true;
}
public function bootstrapDrupalDatabase(BootstrapManager $manager)
{
// D8 omits this bootstrap level as nothing special needs to be done.
parent::bootstrapDrupalDatabase($manager);
}
public function bootstrapDrupalConfiguration(BootstrapManager $manager, AnnotationData $annotationData = null)
{
// Default to the standard kernel.
$kernel = Kernels::DRUPAL;
if (!empty($annotationData)) {
$kernel = $annotationData->get('kernel', Kernels::DRUPAL);
}
$classloader = $this->autoloader();
$request = $this->getRequest();
$kernel_factory = Kernels::getKernelFactory($kernel);
$allow_dumping = $kernel !== Kernels::UPDATE;
/** @var \Drupal\Core\DrupalKernelInterface kernel */
$this->kernel = $kernel_factory($request, $classloader, 'prod', $allow_dumping);
// Include Drush services in the container.
// @see Drush\Drupal\DrupalKernel::addServiceModifier()
$this->kernel->addServiceModifier(new DrushServiceModifier());
// Unset drupal error handler and restore Drush's one.
restore_error_handler();
// Disable automated cron if the module is enabled.
$GLOBALS['config']['automated_cron.settings']['interval'] = 0;
parent::bootstrapDrupalConfiguration($manager);
}
public function bootstrapDrupalFull(BootstrapManager $manager)
{
$this->logger->debug(dt('Start bootstrap of the Drupal Kernel.'));
$this->kernel->boot();
$this->kernel->prepareLegacyRequest($this->getRequest());
$this->logger->debug(dt('Finished bootstrap of the Drupal Kernel.'));
parent::bootstrapDrupalFull($manager);
$this->addLogger();
$this->addDrupalModuleDrushCommands($manager);
}
public function addDrupalModuleDrushCommands($manager)
{
$application = Drush::getApplication();
$runner = Drush::runner();
// We have to get the service command list from the container, because
// it is constructed in an indirect way during the container initialization.
// The upshot is that the list of console commands is not available
// until after $kernel->boot() is called.
$container = \Drupal::getContainer();
// Set the command info alterers.
if ($container->has(DrushServiceModifier::DRUSH_COMMAND_INFO_ALTERER_SERVICES)) {
$serviceCommandInfoAltererlist = $container->get(DrushServiceModifier::DRUSH_COMMAND_INFO_ALTERER_SERVICES);
$commandFactory = Drush::commandFactory();
foreach ($serviceCommandInfoAltererlist->getCommandList() as $altererHandler) {
$commandFactory->addCommandInfoAlterer($altererHandler);
$this->logger->debug(dt('Commands are potentially altered in !class.', ['!class' => get_class($altererHandler)]));
}
}
$serviceCommandlist = $container->get(DrushServiceModifier::DRUSH_CONSOLE_SERVICES);
if ($container->has(DrushServiceModifier::DRUSH_CONSOLE_SERVICES)) {
foreach ($serviceCommandlist->getCommandList() as $command) {
$manager->inflect($command);
$this->logger->log(LogLevel::DEBUG_NOTIFY, dt('Add a command: !name', ['!name' => $command->getName()]));
$application->add($command);
}
}
// Do the same thing with the annotation commands.
if ($container->has(DrushServiceModifier::DRUSH_COMMAND_SERVICES)) {
$serviceCommandlist = $container->get(DrushServiceModifier::DRUSH_COMMAND_SERVICES);
foreach ($serviceCommandlist->getCommandList() as $commandHandler) {
$manager->inflect($commandHandler);
$this->logger->log(LogLevel::DEBUG_NOTIFY, dt('Add a commandfile class: !name', ['!name' => get_class($commandHandler)]));
$runner->registerCommandClass($application, $commandHandler);
}
}
}
/**
* {@inheritdoc}
*/
public function terminate()
{
parent::terminate();
if ($this->kernel) {
$response = Response::create('');
$this->kernel->terminate($this->getRequest(), $response);
}
}
}