Newer
Older
<?php
namespace Drupal\Core;
Alex Pott
committed
use Drupal\Component\Assertion\Handle;
use Drupal\Component\FileCache\FileCacheFactory;
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;
Alex Pott
committed
use Symfony\Component\ClassLoader\ApcClassLoader;
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 {
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
/**
* 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.
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
* @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, $app_root = NULL) {
$kernel = new static($environment, $class_loader, $allow_dumping, $app_root);
static::bootEnvironment($app_root);
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.
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
catch
committed
*/
public function __construct($environment, $class_loader, $allow_dumping = TRUE, $app_root = NULL) {
$this->environment = $environment;
catch
committed
$this->classLoader = $class_loader;
catch
committed
$this->allowDumping = $allow_dumping;
if ($app_root === NULL) {
$app_root = static::guessApplicationRoot();
}
$this->root = $app_root;
}
/**
* Determine the application root directory based on assumptions.
*
* @return string
* The application root.
*/
protected static function guessApplicationRoot() {
return dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
}
/**
* 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.
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
*
* @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, $app_root = NULL) {
Alex Pott
committed
if (static::validateHostname($request) === FALSE) {
throw new BadRequestHttpException();
}
if ($app_root === NULL) {
$app_root = static::guessApplicationRoot();
}
// 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($app_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 $app_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($app_root . '/sites/' . $sites[$dir])) {
$dir = $sites[$dir];
}
if (file_exists($app_root . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists($app_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();
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
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
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
// 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
*
* The 'environment' consists of:
* - The kernel environment string.
* - The Drupal version constant.
* - The deployment identifier from settings.php. This allows custom
* deployments to force a container rebuild.
* - The operating system running PHP. This allows compiler passes to optimize
* services for different operating systems.
* - The paths to any additional container YAMLs from settings.php.
*
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'), PHP_OS, serialize(Settings::get('container_yamls')));
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')->error('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.
*
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
*/
public static function bootEnvironment($app_root = NULL) {
if (static::$isEnvironmentInitialized) {
return;
}
// Determine the application root if it's not supplied.
if ($app_root === NULL) {
$app_root = static::guessApplicationRoot();
}
Alex Pott
committed
// Include our bootstrap file.
require_once $app_root . '/core/includes/bootstrap.inc';
Alex Pott
committed
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
// 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.
Alex Pott
committed
Handle::register();
Alex Pott
committed
// Log fatal errors to the test site directory.
ini_set('log_errors', 1);
ini_set('error_log', $app_root . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
catch
committed
// Ensure that a rewritten settings.php is used if opcache is on.
ini_set('opcache.validate_timestamps', 'on');
ini_set('opcache.revalidate_freq', 0);
}
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