Newer
Older
* Contains \Drupal\Core\DrupalKernel.
*/
namespace Drupal\Core;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
catch
committed
use Drupal\Core\Config\BootstrapConfigStorageFactory;
use Drupal\Core\Config\NullStorage;
use Drupal\Core\Database\Database;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
Alex Pott
committed
use Drupal\Core\DependencyInjection\YamlFileLoader;
catch
committed
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\File\MimeType\MimeTypeGuesser;
Angie Byron
committed
use Drupal\Core\Http\TrustedHostsRequestFactory;
catch
committed
use Drupal\Core\Language\Language;
use Drupal\Core\Site\Settings;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Alex Pott
committed
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
Alex Pott
committed
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
use Symfony\Component\Routing\Route;
/**
* The DrupalKernel class is the core of Drupal itself.
*
* This class is responsible for building the Dependency Injection Container and
* also deals with the registration of service providers. It allows registered
* service providers to add their services to the container. Core provides the
* CoreServiceProvider, which, in addition to registering any core services that
* cannot be registered in the core.services.yaml file, adds any compiler passes
* needed by core, e.g. for processing tagged services. Each module can add its
* own service provider, i.e. a class implementing
* Drupal\Core\DependencyInjection\ServiceProvider, to register services to the
* container, or modify existing services.
class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
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
/**
* Holds the class used for dumping the container to a PHP array.
*
* In combination with swapping the container class this is useful to e.g.
* dump to the human-readable PHP array format to debug the container
* definition in an easier way.
*
* @var string
*/
protected $phpArrayDumperClass = '\Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper';
/**
* Holds the default bootstrap container definition.
*
* @var array
*/
protected $defaultBootstrapContainerDefinition = [
'parameters' => [],
'services' => [
'database' => [
'class' => 'Drupal\Core\Database\Connection',
'factory' => 'Drupal\Core\Database\Database::getConnection',
'arguments' => ['default'],
],
'cache.container' => [
'class' => 'Drupal\Core\Cache\DatabaseBackend',
'arguments' => ['@database', '@cache_tags_provider.container', 'container'],
],
'cache_tags_provider.container' => [
'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum',
'arguments' => ['@database'],
],
],
];
/**
* Holds the class used for instantiating the bootstrap container.
*
* @var string
*/
protected $bootstrapContainerClass = '\Drupal\Component\DependencyInjection\PhpArrayContainer';
/**
* Holds the bootstrap container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $bootstrapContainer;
/**
* Holds the container instance.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* The environment, e.g. 'testing', 'install'.
*
* @var string
*/
protected $environment;
/**
* Whether the kernel has been booted.
*
* @var bool
*/
protected $booted = FALSE;
Alex Pott
committed
/**
* Whether essential services have been set up properly by preHandle().
*
* @var bool
*/
protected $prepared = FALSE;
/**
* Holds the list of enabled modules.
*
* @var array
catch
committed
* An associative array whose keys are module names and whose values are
* ignored.
*/
protected $moduleList;
catch
committed
/**
* List of available modules and installation profiles.
catch
committed
*
* @var \Drupal\Core\Extension\Extension[]
*/
catch
committed
protected $moduleData = array();
catch
committed
/**
catch
committed
* The class loader object.
catch
committed
*
* @var \Composer\Autoload\ClassLoader
catch
committed
*/
protected $classLoader;
catch
committed
/**
* Config storage object used for reading enabled modules configuration.
*
* @var \Drupal\Core\Config\StorageInterface
*/
protected $configStorage;
/**
* Whether the container can be dumped.
*
* @var bool
*/
protected $allowDumping;
/**
* Whether the container needs to be rebuilt the next time it is initialized.
*
* @var bool
*/
protected $containerNeedsRebuild = FALSE;
catch
committed
/**
* Whether the container needs to be dumped once booting is complete.
*
* @var bool
*/
protected $containerNeedsDumping;
Alex Pott
committed
/**
* List of discovered services.yml pathnames.
*
* This is a nested array whose top-level keys are 'app' and 'site', denoting
* the origin of a service provider. Site-specific providers have to be
* collected separately, because they need to be processed last, so as to be
* able to override services from application service providers.
Alex Pott
committed
*
* @var array
*/
protected $serviceYamls;
/**
* List of discovered service provider class names or objects.
*
* This is a nested array whose top-level keys are 'app' and 'site', denoting
* the origin of a service provider. Site-specific providers have to be
* collected separately, because they need to be processed last, so as to be
* able to override services from application service providers.
*
* Allowing objects is for example used to allow
* \Drupal\KernelTests\KernelTestBase to register itself as service provider.
*
* @var array
*/
protected $serviceProviderClasses;
/**
* List of instantiated service provider classes.
*
* @see \Drupal\Core\DrupalKernel::$serviceProviderClasses
*
* @var array
*/
protected $serviceProviders;
/**
* Whether the PHP environment has been initialized.
*
* This legacy phase can only be booted once because it sets session INI
* settings. If a session has already been started, re-generating these
* settings would break the session.
*
* @var bool
*/
protected static $isEnvironmentInitialized = FALSE;
/**
* The site directory.
*
* @var string
*/
protected $sitePath;
/**
* The app root.
*
* @var string
*/
protected $root;
/**
* Create a DrupalKernel object from a request.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request.
* @param $class_loader
* The class loader. Normally Composer's ClassLoader, as included by the
* front controller, but may also be decorated; e.g.,
* \Symfony\Component\ClassLoader\ApcClassLoader.
* @param string $environment
* String indicating the environment, e.g. 'prod' or 'dev'.
* @param bool $allow_dumping
* (optional) FALSE to stop the container from being written to or read
* from disk. Defaults to TRUE.
* @return static
*
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
* In case the host name in the request is not trusted.
*/
public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE) {
$kernel = new static($environment, $class_loader, $allow_dumping);
static::bootEnvironment();
Alex Pott
committed
$kernel->initializeSettings($request);
return $kernel;
}
/**
* Constructs a DrupalKernel object.
*
* @param string $environment
* String indicating the environment, e.g. 'prod' or 'dev'.
* @param $class_loader
* The class loader. Normally \Composer\Autoload\ClassLoader, as included by
* the front controller, but may also be decorated; e.g.,
* \Symfony\Component\ClassLoader\ApcClassLoader.
catch
committed
* @param bool $allow_dumping
* (optional) FALSE to stop the container from being written to or read
* from disk. Defaults to TRUE.
catch
committed
*/
public function __construct($environment, $class_loader, $allow_dumping = TRUE) {
$this->environment = $environment;
catch
committed
$this->classLoader = $class_loader;
catch
committed
$this->allowDumping = $allow_dumping;
$this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
}
/**
* Returns the appropriate site directory for a request.
*
* Once the kernel has been created DrupalKernelInterface::getSitePath() is
* preferred since it gets the statically cached result of this method.
*
* Site directories contain all site specific code. This includes settings.php
* for bootstrap level configuration, file configuration stores, public file
* storage and site specific modules and themes.
*
* Finds a matching site directory file by stripping the website's hostname
* from left to right and pathname from right to left. By default, the
* directory must contain a 'settings.php' file for it to match. If the
* parameter $require_settings is set to FALSE, then a directory without a
* 'settings.php' file will match as well. The first configuration file found
* will be used and the remaining ones will be ignored. If no configuration
* file is found, returns a default value 'sites/default'. See
* default.settings.php for examples on how the URL is converted to a
* directory.
*
* If a file named sites.php is present in the sites directory, it will be
* loaded prior to scanning for directories. That file can define aliases in
* an associative array named $sites. The array is written in the format
* '<port>.<domain>.<path>' => 'directory'. As an example, to create a
* directory alias for https://www.drupal.org:8080/mysite/test whose
* configuration file is in sites/example.com, the array should be defined as:
* @code
* $sites = array(
* '8080.www.drupal.org.mysite.test' => 'example.com',
* );
* @endcode
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
* @param bool $require_settings
* Only directories with an existing settings.php file will be recognized.
* Defaults to TRUE. During initial installation, this is set to FALSE so
* that Drupal can detect a matching directory, then create a new
* settings.php file in it.
*
* @return string
* The path of the matching directory.
*
Alex Pott
committed
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
* In case the host name in the request is invalid.
*
* @see \Drupal\Core\DrupalKernelInterface::getSitePath()
* @see \Drupal\Core\DrupalKernelInterface::setSitePath()
* @see default.settings.php
* @see example.sites.php
*/
public static function findSitePath(Request $request, $require_settings = TRUE) {
Alex Pott
committed
if (static::validateHostname($request) === FALSE) {
throw new BadRequestHttpException();
}
// Check for a simpletest override.
if ($test_prefix = drupal_valid_test_ua()) {
return 'sites/simpletest/' . substr($test_prefix, 10);
}
// Determine whether multi-site functionality is enabled.
if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
return 'sites/default';
}
// Otherwise, use find the site path using the request.
$script_name = $request->server->get('SCRIPT_NAME');
if (!$script_name) {
$script_name = $request->server->get('SCRIPT_FILENAME');
}
$http_host = $request->getHttpHost();
$sites = array();
include DRUPAL_ROOT . '/sites/sites.php';
$uri = explode('/', $script_name);
$server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
for ($i = count($uri) - 1; $i > 0; $i--) {
for ($j = count($server); $j > 0; $j--) {
$dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) {
$dir = $sites[$dir];
}
if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) {
return "sites/$dir";
}
}
}
return 'sites/default';
}
/**
* {@inheritdoc}
*/
public function setSitePath($path) {
Alex Pott
committed
if ($this->booted) {
throw new \LogicException('Site path cannot be changed after calling boot()');
}
$this->sitePath = $path;
}
/**
* {@inheritdoc}
*/
public function getSitePath() {
return $this->sitePath;
}
/**
* {@inheritdoc}
*/
public function getAppRoot() {
return $this->root;
}
catch
committed
/**
* {@inheritdoc}
catch
committed
*/
public function boot() {
if ($this->booted) {
return $this;
}
// Ensure that findSitePath is set.
if (!$this->sitePath) {
throw new \Exception('Kernel does not have site path set before calling boot()');
// Initialize the FileCacheFactory component. We have to do it here instead
// of in \Drupal\Component\FileCache\FileCacheFactory because we can not use
// the Settings object in a component.
$configuration = Settings::get('file_cache');
// Provide a default configuration, if not set.
if (!isset($configuration['default'])) {
$configuration['default'] = [
'class' => '\Drupal\Component\FileCache\FileCache',
'cache_backend_class' => NULL,
'cache_backend_configuration' => [],
];
// @todo Use extension_loaded('apcu') for non-testbot
// https://www.drupal.org/node/2447753.
Alex Pott
committed
if (function_exists('apcu_fetch')) {
$configuration['default']['cache_backend_class'] = '\Drupal\Component\FileCache\ApcuFileCacheBackend';
}
}
FileCacheFactory::setConfiguration($configuration);
FileCacheFactory::setPrefix(Settings::getApcuPrefix('file_cache', $this->root));
$this->bootstrapContainer = new $this->bootstrapContainerClass(Settings::get('bootstrap_container_definition', $this->defaultBootstrapContainerDefinition));
// Initialize the container.
catch
committed
$this->initializeContainer();
// Ensure mt_rand() is reseeded to prevent random values from one page load
// being exploited to predict random values in subsequent page loads.
$seed = unpack("L", Crypt::randomBytes(4));
mt_srand($seed[1]);
catch
committed
$this->booted = TRUE;
return $this;
catch
committed
}
* {@inheritdoc}
public function shutdown() {
if (FALSE === $this->booted) {
return;
}
$this->container->get('stream_wrapper_manager')->unregister();
$this->booted = FALSE;
$this->container = NULL;
$this->moduleList = NULL;
$this->moduleData = array();
}
/**
* {@inheritdoc}
*/
public function getContainer() {
return $this->container;
}
/**
* {@inheritdoc}
*/
public function setContainer(ContainerInterface $container = NULL) {
if (isset($this->container)) {
throw new \Exception('The container should not override an existing container.');
}
if ($this->booted) {
throw new \Exception('The container cannot be set after a booted kernel.');
}
$this->container = $container;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCachedContainerDefinition() {
$cache = $this->bootstrapContainer->get('cache.container')->get($this->getContainerCacheKey());
if ($cache) {
return $cache->data;
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function loadLegacyIncludes() {
require_once $this->root . '/core/includes/common.inc';
require_once $this->root . '/core/includes/database.inc';
require_once $this->root . '/core/includes/module.inc';
require_once $this->root . '/core/includes/theme.inc';
require_once $this->root . '/core/includes/pager.inc';
require_once $this->root . '/core/includes/menu.inc';
require_once $this->root . '/core/includes/tablesort.inc';
require_once $this->root . '/core/includes/file.inc';
require_once $this->root . '/core/includes/unicode.inc';
require_once $this->root . '/core/includes/form.inc';
require_once $this->root . '/core/includes/errors.inc';
require_once $this->root . '/core/includes/schema.inc';
require_once $this->root . '/core/includes/entity.inc';
}
/**
Dries Buytaert
committed
* {@inheritdoc}
*/
Dries Buytaert
committed
public function preHandle(Request $request) {
$this->loadLegacyIncludes();
// Load all enabled modules.
$this->container->get('module_handler')->loadAll();
// Register stream wrappers.
$this->container->get('stream_wrapper_manager')->register();
// Initialize legacy request globals.
$this->initializeRequestGlobals($request);
// Put the request on the stack.
$this->container->get('request_stack')->push($request);
Alex Pott
committed
// Set the allowed protocols.
UrlHelper::setAllowedProtocols($this->container->getParameter('filter_protocols'));
// Override of Symfony's mime type guesser singleton.
MimeTypeGuesser::registerWithSymfonyGuesser($this->container);
Alex Pott
committed
$this->prepared = TRUE;
}
/**
* {@inheritdoc}
*/
public function discoverServiceProviders() {
$this->serviceYamls = array(
'app' => array(),
'site' => array(),
$this->serviceProviderClasses = array(
'app' => array(),
'site' => array(),
);
$this->serviceYamls['app']['core'] = 'core/core.services.yml';
$this->serviceProviderClasses['app']['core'] = 'Drupal\Core\CoreServiceProvider';
// Retrieve enabled modules and register their namespaces.
catch
committed
if (!isset($this->moduleList)) {
$extensions = $this->getConfigStorage()->read('core.extension');
$this->moduleList = isset($extensions['module']) ? $extensions['module'] : array();
catch
committed
}
Alex Pott
committed
$module_filenames = $this->getModuleFileNames();
$this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($module_filenames));
// Load each module's serviceProvider class.
foreach ($module_filenames as $module => $filename) {
$name = "{$camelized}ServiceProvider";
$class = "Drupal\\{$module}\\{$name}";
if (class_exists($class)) {
$this->serviceProviderClasses['app'][$module] = $class;
$filename = dirname($filename) . "/$module.services.yml";
Alex Pott
committed
if (file_exists($filename)) {
$this->serviceYamls['app'][$module] = $filename;
Alex Pott
committed
}
// Add site-specific service providers.
if (!empty($GLOBALS['conf']['container_service_providers'])) {
foreach ($GLOBALS['conf']['container_service_providers'] as $class) {
if ((is_string($class) && class_exists($class)) || (is_object($class) && ($class instanceof ServiceProviderInterface || $class instanceof ServiceModifierInterface))) {
$this->serviceProviderClasses['site'][] = $class;
}
catch
committed
}
}
$this->addServiceFiles(Settings::get('container_yamls', []));
}
/**
* {@inheritdoc}
*/
public function getServiceProviders($origin) {
return $this->serviceProviders[$origin];
}
/**
* {@inheritdoc}
*/
public function terminate(Request $request, Response $response) {
Alex Pott
committed
// Only run terminate() when essential services have been set up properly
// by preHandle() before.
if (FALSE === $this->prepared) {
return;
}
if ($this->getHttpKernel() instanceof TerminableInterface) {
$this->getHttpKernel()->terminate($request, $response);
}
}
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
Alex Pott
committed
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
// Ensure sane PHP environment variables.
static::bootEnvironment();
try {
$this->initializeSettings($request);
// Redirect the user to the installation script if Drupal has not been
// installed yet (i.e., if no $databases array has been defined in the
// settings.php file) and we are not already installing.
if (!Database::getConnectionInfo() && !drupal_installation_attempted() && PHP_SAPI !== 'cli') {
$response = new RedirectResponse($request->getBasePath() . '/core/install.php');
}
else {
$this->boot();
$response = $this->getHttpKernel()->handle($request, $type, $catch);
}
}
catch (\Exception $e) {
if ($catch === FALSE) {
throw $e;
}
$response = $this->handleException($e, $request, $type);
}
// Adapt response headers to the current request.
$response->prepare($request);
return $response;
}
/**
* Converts an exception into a response.
*
* @param \Exception $e
* An exception
* @param Request $request
* A Request instance
* @param int $type
* The type of the request (one of HttpKernelInterface::MASTER_REQUEST or
* HttpKernelInterface::SUB_REQUEST)
*
* @return Response
* A Response instance
Alex Pott
committed
*
* @throws \Exception
* If the passed in exception cannot be turned into a response.
Alex Pott
committed
*/
protected function handleException(\Exception $e, $request, $type) {
if ($e instanceof HttpExceptionInterface) {
$response = new Response($e->getMessage(), $e->getStatusCode());
$response->headers->add($e->getHeaders());
return $response;
}
else {
Alex Pott
committed
throw $e;
Alex Pott
committed
}
}
/**
* {@inheritdoc}
*/
public function prepareLegacyRequest(Request $request) {
$this->boot();
$this->preHandle($request);
Alex Pott
committed
// Setup services which are normally initialized from within stack
// middleware or during the request kernel event.
if (PHP_SAPI !== 'cli') {
$request->setSession($this->container->get('session'));
}
$request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('<none>'));
$request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<none>');
$this->container->get('request_stack')->push($request);
$this->container->get('router.request_context')->fromRequest($request);
return $this;
}
catch
committed
/**
* Returns module data on the filesystem.
*
* @param $module
* The name of the module.
*
* @return \Drupal\Core\Extension\Extension|bool
* Returns an Extension object if the module is found, FALSE otherwise.
catch
committed
*/
protected function moduleData($module) {
if (!$this->moduleData) {
// First, find profiles.
$listing = new ExtensionDiscovery($this->root);
catch
committed
$listing->setProfileDirectories(array());
$all_profiles = $listing->scan('profile');
$profiles = array_intersect_key($all_profiles, $this->moduleList);
catch
committed
// If a module is within a profile directory but specifies another
// profile for testing, it needs to be found in the parent profile.
$settings = $this->getConfigStorage()->read('simpletest.settings');
catch
committed
$parent_profile = !empty($settings['parent_profile']) ? $settings['parent_profile'] : NULL;
if ($parent_profile && !isset($profiles[$parent_profile])) {
catch
committed
// In case both profile directories contain the same extension, the
// actual profile always has precedence.
catch
committed
$profiles = array($parent_profile => $all_profiles[$parent_profile]) + $profiles;
catch
committed
}
catch
committed
$profile_directories = array_map(function ($profile) {
return $profile->getPath();
}, $profiles);
$listing->setProfileDirectories($profile_directories);
catch
committed
// Now find modules.
catch
committed
$this->moduleData = $profiles + $listing->scan('module');
catch
committed
}
return isset($this->moduleData[$module]) ? $this->moduleData[$module] : FALSE;
}
Angie Byron
committed
/**
* Implements Drupal\Core\DrupalKernelInterface::updateModules().
*
* @todo Remove obsolete $module_list parameter. Only $module_filenames is
* needed.
Angie Byron
committed
*/
public function updateModules(array $module_list, array $module_filenames = array()) {
$this->moduleList = $module_list;
foreach ($module_filenames as $name => $extension) {
$this->moduleData[$name] = $extension;
catch
committed
}
Angie Byron
committed
// If we haven't yet booted, we don't need to do anything: the new module
// list will take effect when boot() is called. However we set a
// flag that the container needs a rebuild, so that a potentially cached
// container is not used. If we have already booted, then rebuild the
// container in order to refresh the serviceProvider list and container.
$this->containerNeedsRebuild = TRUE;
Angie Byron
committed
if ($this->booted) {
$this->initializeContainer();
Angie Byron
committed
}
}
catch
committed
/**
* Returns the container cache key based on the environment.
catch
committed
*
* @return string
* The cache key used for the service container.
catch
committed
*/
protected function getContainerCacheKey() {
$parts = array('service_container', $this->environment, \Drupal::VERSION, Settings::get('deployment_identifier'));
return implode(':', $parts);
Alex Pott
committed
}
/**
* Returns the kernel parameters.
*
* @return array An array of kernel parameters
*/
protected function getKernelParameters() {
return array(
'kernel.environment' => $this->environment,
);
}
/**
* Initializes the service container.
*
* @return \Symfony\Component\DependencyInjection\ContainerInterface
protected function initializeContainer() {
$this->containerNeedsDumping = FALSE;
Alex Pott
committed
$session_started = FALSE;
if (isset($this->container)) {
// Save the id of the currently logged in user.
if ($this->container->initialized('current_user')) {
$current_user_id = $this->container->get('current_user')->id();
}
Alex Pott
committed
// If there is a session, close and save it.
if ($this->container->initialized('session')) {
$session = $this->container->get('session');
if ($session->isStarted()) {
$session_started = TRUE;
$session->save();
Alex Pott
committed
unset($session);
}
catch
committed
// If we haven't booted yet but there is a container, then we're asked to
// boot the container injected via setContainer().
// @see \Drupal\KernelTests\KernelTestBase::setUp()
if (isset($this->container) && !$this->booted) {
$container = $this->container;
}
// If the module list hasn't already been set in updateModules and we are
// not forcing a rebuild, then try and load the container from the cache.
if (empty($this->moduleList) && !$this->containerNeedsRebuild) {
$container_definition = $this->getCachedContainerDefinition();
// If there is no container and no cached container definition, build a new
// one from scratch.
if (!isset($container) && !isset($container_definition)) {
$container = $this->compileContainer();
// Only dump the container if dumping is allowed. This is useful for
// KernelTestBase, which never wants to use the real container, but always
// the container builder.
if ($this->allowDumping) {
$dumper = new $this->phpArrayDumperClass($container);
$container_definition = $dumper->getArray();
}
}
// The container was rebuilt successfully.
$this->containerNeedsRebuild = FALSE;
// Only create a new class if we have a container definition.
if (isset($container_definition)) {
$class = Settings::get('container_base_class', '\Drupal\Core\DependencyInjection\Container');
$container = new $class($container_definition);
}
$this->attachSynthetic($container);
$this->container = $container;
Alex Pott
committed
if ($session_started) {
$this->container->get('session')->start();
Alex Pott
committed
// The request stack is preserved across container rebuilds. Reinject the
// new session into the master request if one was present before.
if (($request_stack = $this->container->get('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE))) {
if ($request = $request_stack->getMasterRequest()) {
if ($request->hasSession()) {
$request->setSession($this->container->get('session'));
}
}
}
if (!empty($current_user_id)) {
$this->container->get('current_user')->setInitialAccountId($current_user_id);
}
\Drupal::setContainer($this->container);
// If needs dumping flag was set, dump the container.
if ($this->containerNeedsDumping && !$this->cacheDrupalContainer($container_definition)) {
$this->container->get('logger.factory')->get('DrupalKernel')->notice('Container cannot be saved to cache.');
return $this->container;
}
/**
* Setup a consistent PHP environment.
*
* This method sets PHP environment options we want to be sure are set
* correctly for security or just saneness.
*/
public static function bootEnvironment() {
if (static::$isEnvironmentInitialized) {
return;
}
Alex Pott
committed
// Include our bootstrap file.
$core_root = dirname(dirname(dirname(__DIR__)));
require_once $core_root . '/includes/bootstrap.inc';
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
// Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
error_reporting(E_STRICT | E_ALL);
// Override PHP settings required for Drupal to work properly.
// sites/default/default.settings.php contains more runtime settings.
// The .htaccess file contains settings that cannot be changed at runtime.
// Use session cookies, not transparent sessions that puts the session id in
// the query string.
ini_set('session.use_cookies', '1');
ini_set('session.use_only_cookies', '1');
ini_set('session.use_trans_sid', '0');
// Don't send HTTP headers using PHP's session handler.
// Send an empty string to disable the cache limiter.
ini_set('session.cache_limiter', '');
// Use httponly session cookies.
ini_set('session.cookie_httponly', '1');
// Set sane locale settings, to ensure consistent string, dates, times and
// numbers handling.
setlocale(LC_ALL, 'C');
// Detect string handling method.
Unicode::check();
// Indicate that code is operating in a test child site.
if (!defined('DRUPAL_TEST_IN_CHILD_SITE')) {
if ($test_prefix = drupal_valid_test_ua()) {
// Only code that interfaces directly with tests should rely on this
// constant; e.g., the error/exception handler conditionally adds further
// error information into HTTP response headers that are consumed by
// Simpletest's internal browser.
define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
Alex Pott
committed
// Web tests are to be conducted with runtime assertions active.
assert_options(ASSERT_ACTIVE, TRUE);
// Now synchronize PHP 5 and 7's handling of assertions as much as
// possible.
\Drupal\Component\Assertion\Handle::register();
// Log fatal errors to the test site directory.
ini_set('log_errors', 1);
ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
}
else {
// Ensure that no other code defines this.
define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
}
}
// Set the Drupal custom error handler.
set_error_handler('_drupal_error_handler');
set_exception_handler('_drupal_exception_handler');
static::$isEnvironmentInitialized = TRUE;
}
Alex Pott
committed
/**
* Locate site path and initialize settings singleton.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
*
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
* In case the host name in the request is not trusted.
*/
protected function initializeSettings(Request $request) {
$site_path = static::findSitePath($request);
$this->setSitePath($site_path);
$class_loader_class = get_class($this->classLoader);
Settings::initialize($this->root, $site_path, $this->classLoader);
// Initialize our list of trusted HTTP Host headers to protect against
// header attacks.
$host_patterns = Settings::get('trusted_host_patterns', array());
if (PHP_SAPI !== 'cli' && !empty($host_patterns)) {
if (static::setupTrustedHosts($request, $host_patterns) === FALSE) {
throw new BadRequestHttpException('The provided host name is not valid for this server.');
}
}
Alex Pott
committed
// If the class loader is still the same, possibly upgrade to the APCu class
Alex Pott
committed
// loader.
if ($class_loader_class == get_class($this->classLoader)
&& Settings::get('class_loader_auto_detect', TRUE)
Alex Pott
committed
&& function_exists('apcu_fetch')) {
Alex Pott
committed
$prefix = Settings::getApcuPrefix('class_loader', $this->root);
$apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $this->classLoader);
$this->classLoader->unregister();
$apc_loader->register();
$this->classLoader = $apc_loader;
}
}
/**
* Bootstraps the legacy global request variables.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
*
* @todo D8: Eliminate this entirely in favor of Request object.
*/
protected function initializeRequestGlobals(Request $request) {
global $base_url;
// Set and derived from $base_url by this function.
global $base_path, $base_root;
global $base_secure_url, $base_insecure_url;
catch
committed
// Create base URL.
$base_root = $request->getSchemeAndHttpHost();
$base_url = $base_root;