"Fossies" - the Fresh Open Source Software Archive

Member "drupal-9.1.0-rc1/core/lib/Drupal/Core/DrupalKernel.php" (18 Nov 2020, 54884 Bytes) of package /linux/www/drupal-9.1.0-rc1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "DrupalKernel.php" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 9.0.8_vs_9.1.0-rc1.

    1 <?php
    2 
    3 namespace Drupal\Core;
    4 
    5 use Composer\Autoload\ClassLoader;
    6 use Drupal\Component\Assertion\Handle;
    7 use Drupal\Component\EventDispatcher\Event;
    8 use Drupal\Component\FileCache\FileCacheFactory;
    9 use Drupal\Component\Utility\UrlHelper;
   10 use Drupal\Core\Cache\DatabaseBackend;
   11 use Drupal\Core\Config\BootstrapConfigStorageFactory;
   12 use Drupal\Core\Config\NullStorage;
   13 use Drupal\Core\Database\Database;
   14 use Drupal\Core\DependencyInjection\ContainerBuilder;
   15 use Drupal\Core\DependencyInjection\ServiceModifierInterface;
   16 use Drupal\Core\DependencyInjection\ServiceProviderInterface;
   17 use Drupal\Core\DependencyInjection\YamlFileLoader;
   18 use Drupal\Core\Extension\ExtensionDiscovery;
   19 use Drupal\Core\File\MimeType\MimeTypeGuesser;
   20 use Drupal\Core\Http\TrustedHostsRequestFactory;
   21 use Drupal\Core\Installer\InstallerKernel;
   22 use Drupal\Core\Installer\InstallerRedirectTrait;
   23 use Drupal\Core\Language\Language;
   24 use Drupal\Core\Security\PharExtensionInterceptor;
   25 use Drupal\Core\Security\RequestSanitizer;
   26 use Drupal\Core\Site\Settings;
   27 use Drupal\Core\Test\TestDatabase;
   28 use Symfony\Component\DependencyInjection\ContainerInterface;
   29 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
   30 use Symfony\Component\HttpFoundation\RedirectResponse;
   31 use Symfony\Component\HttpFoundation\Request;
   32 use Symfony\Component\HttpFoundation\Response;
   33 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
   34 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
   35 use Symfony\Component\HttpKernel\TerminableInterface;
   36 use TYPO3\PharStreamWrapper\Manager as PharStreamWrapperManager;
   37 use TYPO3\PharStreamWrapper\Behavior as PharStreamWrapperBehavior;
   38 use TYPO3\PharStreamWrapper\PharStreamWrapper;
   39 
   40 /**
   41  * The DrupalKernel class is the core of Drupal itself.
   42  *
   43  * This class is responsible for building the Dependency Injection Container and
   44  * also deals with the registration of service providers. It allows registered
   45  * service providers to add their services to the container. Core provides the
   46  * CoreServiceProvider, which, in addition to registering any core services that
   47  * cannot be registered in the core.services.yaml file, adds any compiler passes
   48  * needed by core, e.g. for processing tagged services. Each module can add its
   49  * own service provider, i.e. a class implementing
   50  * Drupal\Core\DependencyInjection\ServiceProvider, to register services to the
   51  * container, or modify existing services.
   52  */
   53 class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
   54   use InstallerRedirectTrait;
   55 
   56   /**
   57    * Holds the class used for dumping the container to a PHP array.
   58    *
   59    * In combination with swapping the container class this is useful to e.g.
   60    * dump to the human-readable PHP array format to debug the container
   61    * definition in an easier way.
   62    *
   63    * @var string
   64    */
   65   protected $phpArrayDumperClass = '\Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper';
   66 
   67   /**
   68    * Holds the default bootstrap container definition.
   69    *
   70    * @var array
   71    */
   72   protected $defaultBootstrapContainerDefinition = [
   73     'parameters' => [],
   74     'services' => [
   75       'database' => [
   76         'class' => 'Drupal\Core\Database\Connection',
   77         'factory' => 'Drupal\Core\Database\Database::getConnection',
   78         'arguments' => ['default'],
   79       ],
   80       'cache.container' => [
   81         'class' => 'Drupal\Core\Cache\DatabaseBackend',
   82         'arguments' => ['@database', '@cache_tags_provider.container', 'container', DatabaseBackend::MAXIMUM_NONE],
   83       ],
   84       'cache_tags_provider.container' => [
   85         'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum',
   86         'arguments' => ['@database'],
   87       ],
   88     ],
   89   ];
   90 
   91   /**
   92    * Holds the class used for instantiating the bootstrap container.
   93    *
   94    * @var string
   95    */
   96   protected $bootstrapContainerClass = '\Drupal\Component\DependencyInjection\PhpArrayContainer';
   97 
   98   /**
   99    * Holds the bootstrap container.
  100    *
  101    * @var \Symfony\Component\DependencyInjection\ContainerInterface
  102    */
  103   protected $bootstrapContainer;
  104 
  105   /**
  106    * Holds the container instance.
  107    *
  108    * @var \Symfony\Component\DependencyInjection\ContainerInterface
  109    */
  110   protected $container;
  111 
  112   /**
  113    * The environment, e.g. 'testing', 'install'.
  114    *
  115    * @var string
  116    */
  117   protected $environment;
  118 
  119   /**
  120    * Whether the kernel has been booted.
  121    *
  122    * @var bool
  123    */
  124   protected $booted = FALSE;
  125 
  126   /**
  127    * Whether essential services have been set up properly by preHandle().
  128    *
  129    * @var bool
  130    */
  131   protected $prepared = FALSE;
  132 
  133   /**
  134    * Holds the list of enabled modules.
  135    *
  136    * @var array
  137    *   An associative array whose keys are module names and whose values are
  138    *   ignored.
  139    */
  140   protected $moduleList;
  141 
  142   /**
  143    * List of available modules and installation profiles.
  144    *
  145    * @var \Drupal\Core\Extension\Extension[]
  146    */
  147   protected $moduleData = [];
  148 
  149   /**
  150    * The class loader object.
  151    *
  152    * @var \Composer\Autoload\ClassLoader
  153    */
  154   protected $classLoader;
  155 
  156   /**
  157    * Config storage object used for reading enabled modules configuration.
  158    *
  159    * @var \Drupal\Core\Config\StorageInterface
  160    */
  161   protected $configStorage;
  162 
  163   /**
  164    * Whether the container can be dumped.
  165    *
  166    * @var bool
  167    */
  168   protected $allowDumping;
  169 
  170   /**
  171    * Whether the container needs to be rebuilt the next time it is initialized.
  172    *
  173    * @var bool
  174    */
  175   protected $containerNeedsRebuild = FALSE;
  176 
  177   /**
  178    * Whether the container needs to be dumped once booting is complete.
  179    *
  180    * @var bool
  181    */
  182   protected $containerNeedsDumping;
  183 
  184   /**
  185    * List of discovered services.yml pathnames.
  186    *
  187    * This is a nested array whose top-level keys are 'app' and 'site', denoting
  188    * the origin of a service provider. Site-specific providers have to be
  189    * collected separately, because they need to be processed last, so as to be
  190    * able to override services from application service providers.
  191    *
  192    * @var array
  193    */
  194   protected $serviceYamls;
  195 
  196   /**
  197    * List of discovered service provider class names or objects.
  198    *
  199    * This is a nested array whose top-level keys are 'app' and 'site', denoting
  200    * the origin of a service provider. Site-specific providers have to be
  201    * collected separately, because they need to be processed last, so as to be
  202    * able to override services from application service providers.
  203    *
  204    * Allowing objects is for example used to allow
  205    * \Drupal\KernelTests\KernelTestBase to register itself as service provider.
  206    *
  207    * @var array
  208    */
  209   protected $serviceProviderClasses;
  210 
  211   /**
  212    * List of instantiated service provider classes.
  213    *
  214    * @see \Drupal\Core\DrupalKernel::$serviceProviderClasses
  215    *
  216    * @var array
  217    */
  218   protected $serviceProviders;
  219 
  220   /**
  221    * Whether the PHP environment has been initialized.
  222    *
  223    * This legacy phase can only be booted once because it sets session INI
  224    * settings. If a session has already been started, re-generating these
  225    * settings would break the session.
  226    *
  227    * @var bool
  228    */
  229   protected static $isEnvironmentInitialized = FALSE;
  230 
  231   /**
  232    * The site directory.
  233    *
  234    * @var string
  235    */
  236   protected $sitePath;
  237 
  238   /**
  239    * The app root.
  240    *
  241    * @var string
  242    */
  243   protected $root;
  244 
  245   /**
  246    * Create a DrupalKernel object from a request.
  247    *
  248    * @param \Symfony\Component\HttpFoundation\Request $request
  249    *   The request.
  250    * @param $class_loader
  251    *   The class loader. Normally Composer's ClassLoader, as included by the
  252    *   front controller, but may also be decorated.
  253    * @param string $environment
  254    *   String indicating the environment, e.g. 'prod' or 'dev'.
  255    * @param bool $allow_dumping
  256    *   (optional) FALSE to stop the container from being written to or read
  257    *   from disk. Defaults to TRUE.
  258    * @param string $app_root
  259    *   (optional) The path to the application root as a string. If not supplied,
  260    *   the application root will be computed.
  261    *
  262    * @return static
  263    *
  264    * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
  265    *   In case the host name in the request is not trusted.
  266    */
  267   public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE, $app_root = NULL) {
  268     $kernel = new static($environment, $class_loader, $allow_dumping, $app_root);
  269     static::bootEnvironment($app_root);
  270     $kernel->initializeSettings($request);
  271     return $kernel;
  272   }
  273 
  274   /**
  275    * Constructs a DrupalKernel object.
  276    *
  277    * @param string $environment
  278    *   String indicating the environment, e.g. 'prod' or 'dev'.
  279    * @param $class_loader
  280    *   The class loader. Normally \Composer\Autoload\ClassLoader, as included by
  281    *   the front controller, but may also be decorated.
  282    * @param bool $allow_dumping
  283    *   (optional) FALSE to stop the container from being written to or read
  284    *   from disk. Defaults to TRUE.
  285    * @param string $app_root
  286    *   (optional) The path to the application root as a string. If not supplied,
  287    *   the application root will be computed.
  288    */
  289   public function __construct($environment, $class_loader, $allow_dumping = TRUE, $app_root = NULL) {
  290     $this->environment = $environment;
  291     $this->classLoader = $class_loader;
  292     $this->allowDumping = $allow_dumping;
  293     if ($app_root === NULL) {
  294       $app_root = static::guessApplicationRoot();
  295     }
  296     $this->root = $app_root;
  297   }
  298 
  299   /**
  300    * Determine the application root directory based on this file's location.
  301    *
  302    * @return string
  303    *   The application root.
  304    */
  305   protected static function guessApplicationRoot() {
  306     // Determine the application root by:
  307     // - Removing the namespace directories from the path.
  308     // - Getting the path to the directory two levels up from the path
  309     //   determined in the previous step.
  310     return dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);
  311   }
  312 
  313   /**
  314    * Returns the appropriate site directory for a request.
  315    *
  316    * Once the kernel has been created DrupalKernelInterface::getSitePath() is
  317    * preferred since it gets the statically cached result of this method.
  318    *
  319    * Site directories contain all site specific code. This includes settings.php
  320    * for bootstrap level configuration, file configuration stores, public file
  321    * storage and site specific modules and themes.
  322    *
  323    * A file named sites.php must be present in the sites directory for
  324    * multisite. If it doesn't exist, then 'sites/default' will be used.
  325    *
  326    * Finds a matching site directory file by stripping the website's hostname
  327    * from left to right and pathname from right to left. By default, the
  328    * directory must contain a 'settings.php' file for it to match. If the
  329    * parameter $require_settings is set to FALSE, then a directory without a
  330    * 'settings.php' file will match as well. The first configuration file found
  331    * will be used and the remaining ones will be ignored. If no configuration
  332    * file is found, returns a default value 'sites/default'. See
  333    * default.settings.php for examples on how the URL is converted to a
  334    * directory.
  335    *
  336    * The sites.php file in the sites directory can define aliases in an
  337    * associative array named $sites. The array is written in the format
  338    * '<port>.<domain>.<path>' => 'directory'. As an example, to create a
  339    * directory alias for https://www.drupal.org:8080/mysite/test whose
  340    * configuration file is in sites/example.com, the array should be defined as:
  341    * @code
  342    * $sites = array(
  343    *   '8080.www.drupal.org.mysite.test' => 'example.com',
  344    * );
  345    * @endcode
  346    *
  347    * @param \Symfony\Component\HttpFoundation\Request $request
  348    *   The current request.
  349    * @param bool $require_settings
  350    *   Only directories with an existing settings.php file will be recognized.
  351    *   Defaults to TRUE. During initial installation, this is set to FALSE so
  352    *   that Drupal can detect a matching directory, then create a new
  353    *   settings.php file in it.
  354    * @param string $app_root
  355    *   (optional) The path to the application root as a string. If not supplied,
  356    *   the application root will be computed.
  357    *
  358    * @return string
  359    *   The path of the matching directory.
  360    *
  361    * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
  362    *   In case the host name in the request is invalid.
  363    *
  364    * @see \Drupal\Core\DrupalKernelInterface::getSitePath()
  365    * @see \Drupal\Core\DrupalKernelInterface::setSitePath()
  366    * @see default.settings.php
  367    * @see example.sites.php
  368    */
  369   public static function findSitePath(Request $request, $require_settings = TRUE, $app_root = NULL) {
  370     if (static::validateHostname($request) === FALSE) {
  371       throw new BadRequestHttpException();
  372     }
  373 
  374     if ($app_root === NULL) {
  375       $app_root = static::guessApplicationRoot();
  376     }
  377 
  378     // Check for a simpletest override.
  379     if ($test_prefix = drupal_valid_test_ua()) {
  380       $test_db = new TestDatabase($test_prefix);
  381       return $test_db->getTestSitePath();
  382     }
  383 
  384     // Determine whether multi-site functionality is enabled.
  385     if (!file_exists($app_root . '/sites/sites.php')) {
  386       return 'sites/default';
  387     }
  388 
  389     // Otherwise, use find the site path using the request.
  390     $script_name = $request->server->get('SCRIPT_NAME');
  391     if (!$script_name) {
  392       $script_name = $request->server->get('SCRIPT_FILENAME');
  393     }
  394     $http_host = $request->getHttpHost();
  395 
  396     $sites = [];
  397     include $app_root . '/sites/sites.php';
  398 
  399     $uri = explode('/', $script_name);
  400     $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
  401     for ($i = count($uri) - 1; $i > 0; $i--) {
  402       for ($j = count($server); $j > 0; $j--) {
  403         $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
  404         if (isset($sites[$dir]) && file_exists($app_root . '/sites/' . $sites[$dir])) {
  405           $dir = $sites[$dir];
  406         }
  407         if (file_exists($app_root . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists($app_root . '/sites/' . $dir))) {
  408           return "sites/$dir";
  409         }
  410       }
  411     }
  412     return 'sites/default';
  413   }
  414 
  415   /**
  416    * {@inheritdoc}
  417    */
  418   public function setSitePath($path) {
  419     if ($this->booted && $path !== $this->sitePath) {
  420       throw new \LogicException('Site path cannot be changed after calling boot()');
  421     }
  422     $this->sitePath = $path;
  423   }
  424 
  425   /**
  426    * {@inheritdoc}
  427    */
  428   public function getSitePath() {
  429     return $this->sitePath;
  430   }
  431 
  432   /**
  433    * {@inheritdoc}
  434    */
  435   public function getAppRoot() {
  436     return $this->root;
  437   }
  438 
  439   /**
  440    * {@inheritdoc}
  441    */
  442   public function boot() {
  443     if ($this->booted) {
  444       return $this;
  445     }
  446 
  447     // Ensure that findSitePath is set.
  448     if (!$this->sitePath) {
  449       throw new \Exception('Kernel does not have site path set before calling boot()');
  450     }
  451 
  452     // Initialize the FileCacheFactory component. We have to do it here instead
  453     // of in \Drupal\Component\FileCache\FileCacheFactory because we can not use
  454     // the Settings object in a component.
  455     $configuration = Settings::get('file_cache');
  456 
  457     // Provide a default configuration, if not set.
  458     if (!isset($configuration['default'])) {
  459       // @todo Use extension_loaded('apcu') for non-testbot
  460       //  https://www.drupal.org/node/2447753.
  461       if (function_exists('apcu_fetch')) {
  462         $configuration['default']['cache_backend_class'] = '\Drupal\Component\FileCache\ApcuFileCacheBackend';
  463       }
  464     }
  465     FileCacheFactory::setConfiguration($configuration);
  466     FileCacheFactory::setPrefix(Settings::getApcuPrefix('file_cache', $this->root));
  467 
  468     $this->bootstrapContainer = new $this->bootstrapContainerClass(Settings::get('bootstrap_container_definition', $this->defaultBootstrapContainerDefinition));
  469 
  470     // Initialize the container.
  471     $this->initializeContainer();
  472 
  473     // Add the APCu prefix to use to cache found/not-found classes.
  474     if (Settings::get('class_loader_auto_detect', TRUE) && method_exists($this->classLoader, 'setApcuPrefix')) {
  475       // Vary the APCu key by which modules are installed to allow
  476       // class_exists() checks to determine functionality.
  477       $id = 'class_loader:' . crc32(implode(':', array_keys($this->container->getParameter('container.modules'))));
  478       $prefix = Settings::getApcuPrefix($id, $this->root);
  479       $this->classLoader->setApcuPrefix($prefix);
  480     }
  481 
  482     if (in_array('phar', stream_get_wrappers(), TRUE)) {
  483       // Set up a stream wrapper to handle insecurities due to PHP's builtin
  484       // phar stream wrapper. This is not registered as a regular stream wrapper
  485       // to prevent \Drupal\Core\File\FileSystem::validScheme() treating "phar"
  486       // as a valid scheme.
  487       try {
  488         $behavior = new PharStreamWrapperBehavior();
  489         PharStreamWrapperManager::initialize(
  490           $behavior->withAssertion(new PharExtensionInterceptor())
  491         );
  492       }
  493       catch (\LogicException $e) {
  494         // Continue if the PharStreamWrapperManager is already initialized. For
  495         // example, this occurs during a module install.
  496         // @see \Drupal\Core\Extension\ModuleInstaller::install()
  497       }
  498       stream_wrapper_unregister('phar');
  499       stream_wrapper_register('phar', PharStreamWrapper::class);
  500     }
  501 
  502     $this->booted = TRUE;
  503 
  504     return $this;
  505   }
  506 
  507   /**
  508    * {@inheritdoc}
  509    */
  510   public function shutdown() {
  511     if (FALSE === $this->booted) {
  512       return;
  513     }
  514     $this->container->get('stream_wrapper_manager')->unregister();
  515     $this->booted = FALSE;
  516     $this->container = NULL;
  517     $this->moduleList = NULL;
  518     $this->moduleData = [];
  519   }
  520 
  521   /**
  522    * {@inheritdoc}
  523    */
  524   public function getContainer() {
  525     return $this->container;
  526   }
  527 
  528   /**
  529    * {@inheritdoc}
  530    */
  531   public function setContainer(ContainerInterface $container = NULL) {
  532     if (isset($this->container)) {
  533       throw new \Exception('The container should not override an existing container.');
  534     }
  535     if ($this->booted) {
  536       throw new \Exception('The container cannot be set after a booted kernel.');
  537     }
  538 
  539     $this->container = $container;
  540     return $this;
  541   }
  542 
  543   /**
  544    * {@inheritdoc}
  545    */
  546   public function getCachedContainerDefinition() {
  547     $cache = $this->bootstrapContainer->get('cache.container')->get($this->getContainerCacheKey());
  548 
  549     if ($cache) {
  550       return $cache->data;
  551     }
  552 
  553     return NULL;
  554   }
  555 
  556   /**
  557    * {@inheritdoc}
  558    */
  559   public function loadLegacyIncludes() {
  560     require_once $this->root . '/core/includes/common.inc';
  561     require_once $this->root . '/core/includes/module.inc';
  562     require_once $this->root . '/core/includes/theme.inc';
  563     require_once $this->root . '/core/includes/menu.inc';
  564     require_once $this->root . '/core/includes/file.inc';
  565     require_once $this->root . '/core/includes/form.inc';
  566     require_once $this->root . '/core/includes/errors.inc';
  567     require_once $this->root . '/core/includes/schema.inc';
  568   }
  569 
  570   /**
  571    * {@inheritdoc}
  572    */
  573   public function preHandle(Request $request) {
  574     // Sanitize the request.
  575     $request = RequestSanitizer::sanitize(
  576       $request,
  577       (array) Settings::get(RequestSanitizer::SANITIZE_INPUT_SAFE_KEYS, []),
  578       (bool) Settings::get(RequestSanitizer::SANITIZE_LOG, FALSE)
  579     );
  580 
  581     $this->loadLegacyIncludes();
  582 
  583     // Load all enabled modules.
  584     $this->container->get('module_handler')->loadAll();
  585 
  586     // Register stream wrappers.
  587     $this->container->get('stream_wrapper_manager')->register();
  588 
  589     // Initialize legacy request globals.
  590     $this->initializeRequestGlobals($request);
  591 
  592     // Put the request on the stack.
  593     $this->container->get('request_stack')->push($request);
  594 
  595     // Set the allowed protocols.
  596     UrlHelper::setAllowedProtocols($this->container->getParameter('filter_protocols'));
  597 
  598     // Override of Symfony's MIME type guesser singleton.
  599     MimeTypeGuesser::registerWithSymfonyGuesser($this->container);
  600 
  601     $this->prepared = TRUE;
  602   }
  603 
  604   /**
  605    * {@inheritdoc}
  606    */
  607   public function discoverServiceProviders() {
  608     $this->serviceYamls = [
  609       'app' => [],
  610       'site' => [],
  611     ];
  612     $this->serviceProviderClasses = [
  613       'app' => [],
  614       'site' => [],
  615     ];
  616     $this->serviceYamls['app']['core'] = 'core/core.services.yml';
  617     $this->serviceProviderClasses['app']['core'] = 'Drupal\Core\CoreServiceProvider';
  618 
  619     // Retrieve enabled modules and register their namespaces.
  620     if (!isset($this->moduleList)) {
  621       $extensions = $this->getConfigStorage()->read('core.extension');
  622       // If core.extension configuration does not exist and we're not in the
  623       // installer itself, then we need to put the kernel into a pre-installer
  624       // mode. The container should not be dumped because Drupal is yet to be
  625       // installed. The installer service provider is registered to ensure that
  626       // cache and other automatically created tables are not created if
  627       // database settings are available. None of this is required when the
  628       // installer is running because the installer has its own kernel and
  629       // manages the addition of its own service providers.
  630       // @see install_begin_request()
  631       if ($extensions === FALSE && !InstallerKernel::installationAttempted()) {
  632         $this->allowDumping = FALSE;
  633         $this->containerNeedsDumping = FALSE;
  634         $GLOBALS['conf']['container_service_providers']['InstallerServiceProvider'] = 'Drupal\Core\Installer\InstallerServiceProvider';
  635       }
  636       $this->moduleList = isset($extensions['module']) ? $extensions['module'] : [];
  637     }
  638     $module_filenames = $this->getModuleFileNames();
  639     $this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($module_filenames));
  640 
  641     // Load each module's serviceProvider class.
  642     foreach ($module_filenames as $module => $filename) {
  643       $camelized = ContainerBuilder::camelize($module);
  644       $name = "{$camelized}ServiceProvider";
  645       $class = "Drupal\\{$module}\\{$name}";
  646       if (class_exists($class)) {
  647         $this->serviceProviderClasses['app'][$module] = $class;
  648       }
  649       $filename = dirname($filename) . "/$module.services.yml";
  650       if (file_exists($filename)) {
  651         $this->serviceYamls['app'][$module] = $filename;
  652       }
  653     }
  654 
  655     // Add site-specific service providers.
  656     if (!empty($GLOBALS['conf']['container_service_providers'])) {
  657       foreach ($GLOBALS['conf']['container_service_providers'] as $class) {
  658         if ((is_string($class) && class_exists($class)) || (is_object($class) && ($class instanceof ServiceProviderInterface || $class instanceof ServiceModifierInterface))) {
  659           $this->serviceProviderClasses['site'][] = $class;
  660         }
  661       }
  662     }
  663     $this->addServiceFiles(Settings::get('container_yamls', []));
  664   }
  665 
  666   /**
  667    * {@inheritdoc}
  668    */
  669   public function getServiceProviders($origin) {
  670     return $this->serviceProviders[$origin];
  671   }
  672 
  673   /**
  674    * {@inheritdoc}
  675    */
  676   public function terminate(Request $request, Response $response) {
  677     // Only run terminate() when essential services have been set up properly
  678     // by preHandle() before.
  679     if (FALSE === $this->prepared) {
  680       return;
  681     }
  682 
  683     if ($this->getHttpKernel() instanceof TerminableInterface) {
  684       $this->getHttpKernel()->terminate($request, $response);
  685     }
  686   }
  687 
  688   /**
  689    * {@inheritdoc}
  690    */
  691   public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
  692     // Ensure sane PHP environment variables.
  693     static::bootEnvironment();
  694 
  695     try {
  696       $this->initializeSettings($request);
  697 
  698       // Redirect the user to the installation script if Drupal has not been
  699       // installed yet (i.e., if no $databases array has been defined in the
  700       // settings.php file) and we are not already installing.
  701       if (!Database::getConnectionInfo() && !InstallerKernel::installationAttempted() && PHP_SAPI !== 'cli') {
  702         $response = new RedirectResponse($request->getBasePath() . '/core/install.php', 302, ['Cache-Control' => 'no-cache']);
  703       }
  704       else {
  705         $this->boot();
  706         $response = $this->getHttpKernel()->handle($request, $type, $catch);
  707       }
  708     }
  709     catch (\Exception $e) {
  710       if ($catch === FALSE) {
  711         throw $e;
  712       }
  713 
  714       $response = $this->handleException($e, $request, $type);
  715     }
  716 
  717     // Adapt response headers to the current request.
  718     $response->prepare($request);
  719 
  720     return $response;
  721   }
  722 
  723   /**
  724    * Converts an exception into a response.
  725    *
  726    * @param \Exception $e
  727    *   An exception
  728    * @param \Symfony\Component\HttpFoundation\Request $request
  729    *   A Request instance
  730    * @param int $type
  731    *   The type of the request (one of HttpKernelInterface::MASTER_REQUEST or
  732    *   HttpKernelInterface::SUB_REQUEST)
  733    *
  734    * @return \Symfony\Component\HttpFoundation\Response
  735    *   A Response instance
  736    *
  737    * @throws \Exception
  738    *   If the passed in exception cannot be turned into a response.
  739    */
  740   protected function handleException(\Exception $e, $request, $type) {
  741     if ($this->shouldRedirectToInstaller($e, $this->container ? $this->container->get('database') : NULL)) {
  742       return new RedirectResponse($request->getBasePath() . '/core/install.php', 302, ['Cache-Control' => 'no-cache']);
  743     }
  744 
  745     if ($e instanceof HttpExceptionInterface) {
  746       $response = new Response($e->getMessage(), $e->getStatusCode());
  747       $response->headers->add($e->getHeaders());
  748       return $response;
  749     }
  750 
  751     throw $e;
  752   }
  753 
  754   /**
  755    * Returns module data on the filesystem.
  756    *
  757    * @param $module
  758    *   The name of the module.
  759    *
  760    * @return \Drupal\Core\Extension\Extension|bool
  761    *   Returns an Extension object if the module is found, FALSE otherwise.
  762    */
  763   protected function moduleData($module) {
  764     if (!$this->moduleData) {
  765       // First, find profiles.
  766       $listing = new ExtensionDiscovery($this->root);
  767       $listing->setProfileDirectories([]);
  768       $all_profiles = $listing->scan('profile');
  769       $profiles = array_intersect_key($all_profiles, $this->moduleList);
  770 
  771       $profile_directories = array_map(function ($profile) {
  772         return $profile->getPath();
  773       }, $profiles);
  774       $listing->setProfileDirectories($profile_directories);
  775 
  776       // Now find modules.
  777       $this->moduleData = $profiles + $listing->scan('module');
  778     }
  779     return isset($this->moduleData[$module]) ? $this->moduleData[$module] : FALSE;
  780   }
  781 
  782   /**
  783    * Implements Drupal\Core\DrupalKernelInterface::updateModules().
  784    *
  785    * @todo Remove obsolete $module_list parameter. Only $module_filenames is
  786    *   needed.
  787    */
  788   public function updateModules(array $module_list, array $module_filenames = []) {
  789     $pre_existing_module_namespaces = [];
  790     if ($this->booted && is_array($this->moduleList)) {
  791       $pre_existing_module_namespaces = $this->getModuleNamespacesPsr4($this->getModuleFileNames());
  792     }
  793     $this->moduleList = $module_list;
  794     foreach ($module_filenames as $name => $extension) {
  795       $this->moduleData[$name] = $extension;
  796     }
  797 
  798     // If we haven't yet booted, we don't need to do anything: the new module
  799     // list will take effect when boot() is called. However we set a
  800     // flag that the container needs a rebuild, so that a potentially cached
  801     // container is not used. If we have already booted, then rebuild the
  802     // container in order to refresh the serviceProvider list and container.
  803     $this->containerNeedsRebuild = TRUE;
  804     if ($this->booted) {
  805       // We need to register any new namespaces to a new class loader because
  806       // the current class loader might have stored a negative result for a
  807       // class that is now available.
  808       // @see \Composer\Autoload\ClassLoader::findFile()
  809       $new_namespaces = array_diff_key(
  810         $this->getModuleNamespacesPsr4($this->getModuleFileNames()),
  811         $pre_existing_module_namespaces
  812       );
  813       if (!empty($new_namespaces)) {
  814         $additional_class_loader = new ClassLoader();
  815         $this->classLoaderAddMultiplePsr4($new_namespaces, $additional_class_loader);
  816         $additional_class_loader->register();
  817       }
  818 
  819       $this->initializeContainer();
  820     }
  821   }
  822 
  823   /**
  824    * Returns the container cache key based on the environment.
  825    *
  826    * The 'environment' consists of:
  827    * - The kernel environment string.
  828    * - The Drupal version constant.
  829    * - The deployment identifier from settings.php. This allows custom
  830    *   deployments to force a container rebuild.
  831    * - The operating system running PHP. This allows compiler passes to optimize
  832    *   services for different operating systems.
  833    * - The paths to any additional container YAMLs from settings.php.
  834    *
  835    * @return string
  836    *   The cache key used for the service container.
  837    */
  838   protected function getContainerCacheKey() {
  839     $parts = ['service_container', $this->environment, \Drupal::VERSION, Settings::get('deployment_identifier'), PHP_OS, serialize(Settings::get('container_yamls'))];
  840     return implode(':', $parts);
  841   }
  842 
  843   /**
  844    * Returns the kernel parameters.
  845    *
  846    * @return array An array of kernel parameters
  847    */
  848   protected function getKernelParameters() {
  849     return [
  850       'kernel.environment' => $this->environment,
  851     ];
  852   }
  853 
  854   /**
  855    * Initializes the service container.
  856    *
  857    * @return \Symfony\Component\DependencyInjection\ContainerInterface
  858    */
  859   protected function initializeContainer() {
  860     $this->containerNeedsDumping = FALSE;
  861     $session_started = FALSE;
  862     $all_messages = [];
  863     if (isset($this->container)) {
  864       // Save the id of the currently logged in user.
  865       if ($this->container->initialized('current_user')) {
  866         $current_user_id = $this->container->get('current_user')->id();
  867       }
  868 
  869       // If there is a session, close and save it.
  870       if ($this->container->initialized('session')) {
  871         $session = $this->container->get('session');
  872         if ($session->isStarted()) {
  873           $session_started = TRUE;
  874           $session->save();
  875         }
  876         unset($session);
  877       }
  878 
  879       $all_messages = $this->container->get('messenger')->all();
  880     }
  881 
  882     // If we haven't booted yet but there is a container, then we're asked to
  883     // boot the container injected via setContainer().
  884     // @see \Drupal\KernelTests\KernelTestBase::setUp()
  885     if (isset($this->container) && !$this->booted) {
  886       $container = $this->container;
  887     }
  888 
  889     // If the module list hasn't already been set in updateModules and we are
  890     // not forcing a rebuild, then try and load the container from the cache.
  891     if (empty($this->moduleList) && !$this->containerNeedsRebuild) {
  892       $container_definition = $this->getCachedContainerDefinition();
  893     }
  894 
  895     // If there is no container and no cached container definition, build a new
  896     // one from scratch.
  897     if (!isset($container) && !isset($container_definition)) {
  898       $container = $this->compileContainer();
  899 
  900       // Only dump the container if dumping is allowed. This is useful for
  901       // KernelTestBase, which never wants to use the real container, but always
  902       // the container builder.
  903       if ($this->allowDumping) {
  904         $dumper = new $this->phpArrayDumperClass($container);
  905         $container_definition = $dumper->getArray();
  906       }
  907     }
  908 
  909     // The container was rebuilt successfully.
  910     $this->containerNeedsRebuild = FALSE;
  911 
  912     // Only create a new class if we have a container definition.
  913     if (isset($container_definition)) {
  914       // Drupal provides two dynamic parameters to access specific paths that
  915       // are determined from the request.
  916       $container_definition['parameters']['app.root'] = $this->getAppRoot();
  917       $container_definition['parameters']['site.path'] = $this->getSitePath();
  918       $class = Settings::get('container_base_class', '\Drupal\Core\DependencyInjection\Container');
  919       $container = new $class($container_definition);
  920     }
  921 
  922     $this->attachSynthetic($container);
  923 
  924     $this->container = $container;
  925     if ($session_started) {
  926       $this->container->get('session')->start();
  927     }
  928 
  929     // The request stack is preserved across container rebuilds. Reinject the
  930     // new session into the master request if one was present before.
  931     if (($request_stack = $this->container->get('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE))) {
  932       if ($request = $request_stack->getMasterRequest()) {
  933         $subrequest = TRUE;
  934         if ($request->hasSession()) {
  935           $request->setSession($this->container->get('session'));
  936         }
  937       }
  938     }
  939 
  940     if (!empty($current_user_id)) {
  941       $this->container->get('current_user')->setInitialAccountId($current_user_id);
  942     }
  943 
  944     // Re-add messages.
  945     foreach ($all_messages as $type => $messages) {
  946       foreach ($messages as $message) {
  947         $this->container->get('messenger')->addMessage($message, $type);
  948       }
  949     }
  950 
  951     \Drupal::setContainer($this->container);
  952 
  953     // Allow other parts of the codebase to react on container initialization in
  954     // subrequest.
  955     if (!empty($subrequest)) {
  956       $this->container->get('event_dispatcher')->dispatch(new Event(), self::CONTAINER_INITIALIZE_SUBREQUEST_FINISHED);
  957     }
  958 
  959     // If needs dumping flag was set, dump the container.
  960     if ($this->containerNeedsDumping && !$this->cacheDrupalContainer($container_definition)) {
  961       $this->container->get('logger.factory')->get('DrupalKernel')->error('Container cannot be saved to cache.');
  962     }
  963 
  964     return $this->container;
  965   }
  966 
  967   /**
  968    * Setup a consistent PHP environment.
  969    *
  970    * This method sets PHP environment options we want to be sure are set
  971    * correctly for security or just saneness.
  972    *
  973    * @param string $app_root
  974    *   (optional) The path to the application root as a string. If not supplied,
  975    *   the application root will be computed.
  976    */
  977   public static function bootEnvironment($app_root = NULL) {
  978     if (static::$isEnvironmentInitialized) {
  979       return;
  980     }
  981 
  982     // Determine the application root if it's not supplied.
  983     if ($app_root === NULL) {
  984       $app_root = static::guessApplicationRoot();
  985     }
  986 
  987     // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
  988     error_reporting(E_STRICT | E_ALL);
  989 
  990     // Override PHP settings required for Drupal to work properly.
  991     // sites/default/default.settings.php contains more runtime settings.
  992     // The .htaccess file contains settings that cannot be changed at runtime.
  993 
  994     if (PHP_SAPI !== 'cli') {
  995       // Use session cookies, not transparent sessions that puts the session id
  996       // in the query string.
  997       ini_set('session.use_cookies', '1');
  998       ini_set('session.use_only_cookies', '1');
  999       ini_set('session.use_trans_sid', '0');
 1000       // Don't send HTTP headers using PHP's session handler.
 1001       // Send an empty string to disable the cache limiter.
 1002       ini_set('session.cache_limiter', '');
 1003       // Use httponly session cookies.
 1004       ini_set('session.cookie_httponly', '1');
 1005     }
 1006 
 1007     // Set sane locale settings, to ensure consistent string, dates, times and
 1008     // numbers handling.
 1009     setlocale(LC_ALL, 'C');
 1010 
 1011     // Set appropriate configuration for multi-byte strings.
 1012     mb_internal_encoding('utf-8');
 1013     mb_language('uni');
 1014 
 1015     // Indicate that code is operating in a test child site.
 1016     if (!defined('DRUPAL_TEST_IN_CHILD_SITE')) {
 1017       if ($test_prefix = drupal_valid_test_ua()) {
 1018         $test_db = new TestDatabase($test_prefix);
 1019         // Only code that interfaces directly with tests should rely on this
 1020         // constant; e.g., the error/exception handler conditionally adds further
 1021         // error information into HTTP response headers that are consumed by
 1022         // Simpletest's internal browser.
 1023         define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
 1024 
 1025         // Web tests are to be conducted with runtime assertions active.
 1026         assert_options(ASSERT_ACTIVE, TRUE);
 1027         Handle::register();
 1028 
 1029         // Log fatal errors to the test site directory.
 1030         ini_set('log_errors', 1);
 1031         ini_set('error_log', $app_root . '/' . $test_db->getTestSitePath() . '/error.log');
 1032 
 1033         // Ensure that a rewritten settings.php is used if opcache is on.
 1034         ini_set('opcache.validate_timestamps', 'on');
 1035         ini_set('opcache.revalidate_freq', 0);
 1036       }
 1037       else {
 1038         // Ensure that no other code defines this.
 1039         define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
 1040       }
 1041     }
 1042 
 1043     // Set the Drupal custom error handler.
 1044     set_error_handler('_drupal_error_handler');
 1045     set_exception_handler('_drupal_exception_handler');
 1046 
 1047     static::$isEnvironmentInitialized = TRUE;
 1048   }
 1049 
 1050   /**
 1051    * Locate site path and initialize settings singleton.
 1052    *
 1053    * @param \Symfony\Component\HttpFoundation\Request $request
 1054    *   The current request.
 1055    *
 1056    * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
 1057    *   In case the host name in the request is not trusted.
 1058    */
 1059   protected function initializeSettings(Request $request) {
 1060     $site_path = static::findSitePath($request);
 1061     $this->setSitePath($site_path);
 1062     Settings::initialize($this->root, $site_path, $this->classLoader);
 1063 
 1064     // Initialize our list of trusted HTTP Host headers to protect against
 1065     // header attacks.
 1066     $host_patterns = Settings::get('trusted_host_patterns', []);
 1067     if (PHP_SAPI !== 'cli' && !empty($host_patterns)) {
 1068       if (static::setupTrustedHosts($request, $host_patterns) === FALSE) {
 1069         throw new BadRequestHttpException('The provided host name is not valid for this server.');
 1070       }
 1071     }
 1072   }
 1073 
 1074   /**
 1075    * Bootstraps the legacy global request variables.
 1076    *
 1077    * @param \Symfony\Component\HttpFoundation\Request $request
 1078    *   The current request.
 1079    *
 1080    * @todo D8: Eliminate this entirely in favor of Request object.
 1081    */
 1082   protected function initializeRequestGlobals(Request $request) {
 1083     global $base_url;
 1084     // Set and derived from $base_url by this function.
 1085     global $base_path, $base_root;
 1086     global $base_secure_url, $base_insecure_url;
 1087 
 1088     // Create base URL.
 1089     $base_root = $request->getSchemeAndHttpHost();
 1090     $base_url = $base_root;
 1091 
 1092     // For a request URI of '/index.php/foo', $_SERVER['SCRIPT_NAME'] is
 1093     // '/index.php', whereas $_SERVER['PHP_SELF'] is '/index.php/foo'.
 1094     if ($dir = rtrim(dirname($request->server->get('SCRIPT_NAME')), '\/')) {
 1095       // Remove "core" directory if present, allowing install.php,
 1096       // authorize.php, and others to auto-detect a base path.
 1097       $core_position = strrpos($dir, '/core');
 1098       if ($core_position !== FALSE && strlen($dir) - 5 == $core_position) {
 1099         $base_path = substr($dir, 0, $core_position);
 1100       }
 1101       else {
 1102         $base_path = $dir;
 1103       }
 1104       $base_url .= $base_path;
 1105       $base_path .= '/';
 1106     }
 1107     else {
 1108       $base_path = '/';
 1109     }
 1110     $base_secure_url = str_replace('http://', 'https://', $base_url);
 1111     $base_insecure_url = str_replace('https://', 'http://', $base_url);
 1112   }
 1113 
 1114   /**
 1115    * Returns service instances to persist from an old container to a new one.
 1116    */
 1117   protected function getServicesToPersist(ContainerInterface $container) {
 1118     $persist = [];
 1119     foreach ($container->getParameter('persist_ids') as $id) {
 1120       // It's pointless to persist services not yet initialized.
 1121       if ($container->initialized($id)) {
 1122         $persist[$id] = $container->get($id);
 1123       }
 1124     }
 1125     return $persist;
 1126   }
 1127 
 1128   /**
 1129    * Moves persistent service instances into a new container.
 1130    */
 1131   protected function persistServices(ContainerInterface $container, array $persist) {
 1132     foreach ($persist as $id => $object) {
 1133       // Do not override services already set() on the new container, for
 1134       // example 'service_container'.
 1135       if (!$container->initialized($id)) {
 1136         $container->set($id, $object);
 1137       }
 1138     }
 1139   }
 1140 
 1141   /**
 1142    * {@inheritdoc}
 1143    */
 1144   public function rebuildContainer() {
 1145     // Empty module properties and for them to be reloaded from scratch.
 1146     $this->moduleList = NULL;
 1147     $this->moduleData = [];
 1148     $this->containerNeedsRebuild = TRUE;
 1149     return $this->initializeContainer();
 1150   }
 1151 
 1152   /**
 1153    * {@inheritdoc}
 1154    */
 1155   public function invalidateContainer() {
 1156     // An invalidated container needs a rebuild.
 1157     $this->containerNeedsRebuild = TRUE;
 1158 
 1159     // If we have not yet booted, settings or bootstrap services might not yet
 1160     // be available. In that case the container will not be loaded from cache
 1161     // due to the above setting when the Kernel is booted.
 1162     if (!$this->booted) {
 1163       return;
 1164     }
 1165 
 1166     // Also remove the container definition from the cache backend.
 1167     $this->bootstrapContainer->get('cache.container')->deleteAll();
 1168   }
 1169 
 1170   /**
 1171    * Attach synthetic values on to kernel.
 1172    *
 1173    * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
 1174    *   Container object
 1175    *
 1176    * @return \Symfony\Component\DependencyInjection\ContainerInterface
 1177    */
 1178   protected function attachSynthetic(ContainerInterface $container) {
 1179     $persist = [];
 1180     if (isset($this->container)) {
 1181       $persist = $this->getServicesToPersist($this->container);
 1182     }
 1183     $this->persistServices($container, $persist);
 1184 
 1185     // All namespaces must be registered before we attempt to use any service
 1186     // from the container.
 1187     $this->classLoaderAddMultiplePsr4($container->getParameter('container.namespaces'));
 1188 
 1189     $container->set('kernel', $this);
 1190 
 1191     // Set the class loader which was registered as a synthetic service.
 1192     $container->set('class_loader', $this->classLoader);
 1193     return $container;
 1194   }
 1195 
 1196   /**
 1197    * Compiles a new service container.
 1198    *
 1199    * @return \Drupal\Core\DependencyInjection\ContainerBuilder The compiled service container
 1200    */
 1201   protected function compileContainer() {
 1202     // We are forcing a container build so it is reasonable to assume that the
 1203     // calling method knows something about the system has changed requiring the
 1204     // container to be dumped to the filesystem.
 1205     if ($this->allowDumping) {
 1206       $this->containerNeedsDumping = TRUE;
 1207     }
 1208 
 1209     $this->initializeServiceProviders();
 1210     $container = $this->getContainerBuilder();
 1211     $container->set('kernel', $this);
 1212     $container->setParameter('container.modules', $this->getModulesParameter());
 1213     $container->setParameter('install_profile', $this->getInstallProfile());
 1214 
 1215     // Get a list of namespaces and put it onto the container.
 1216     $namespaces = $this->getModuleNamespacesPsr4($this->getModuleFileNames());
 1217     // Add all components in \Drupal\Core and \Drupal\Component that have one of
 1218     // the following directories:
 1219     // - Element
 1220     // - Entity
 1221     // - Plugin
 1222     foreach (['Core', 'Component'] as $parent_directory) {
 1223       $path = 'core/lib/Drupal/' . $parent_directory;
 1224       $parent_namespace = 'Drupal\\' . $parent_directory;
 1225       foreach (new \DirectoryIterator($this->root . '/' . $path) as $component) {
 1226         /** @var $component \DirectoryIterator */
 1227         $pathname = $component->getPathname();
 1228         if (!$component->isDot() && $component->isDir() && (
 1229           is_dir($pathname . '/Plugin') ||
 1230           is_dir($pathname . '/Entity') ||
 1231           is_dir($pathname . '/Element')
 1232         )) {
 1233           $namespaces[$parent_namespace . '\\' . $component->getFilename()] = $path . '/' . $component->getFilename();
 1234         }
 1235       }
 1236     }
 1237     $container->setParameter('container.namespaces', $namespaces);
 1238 
 1239     // Store the default language values on the container. This is so that the
 1240     // default language can be configured using the configuration factory. This
 1241     // avoids the circular dependencies that would created by
 1242     // \Drupal\language\LanguageServiceProvider::alter() and allows the default
 1243     // language to not be English in the installer.
 1244     $default_language_values = Language::$defaultValues;
 1245     if ($system = $this->getConfigStorage()->read('system.site')) {
 1246       if ($default_language_values['id'] != $system['langcode']) {
 1247         $default_language_values = ['id' => $system['langcode']];
 1248       }
 1249     }
 1250     $container->setParameter('language.default_values', $default_language_values);
 1251 
 1252     // Register synthetic services.
 1253     $container->register('class_loader')->setSynthetic(TRUE);
 1254     $container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE);
 1255     $container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE);
 1256 
 1257     // Register application services.
 1258     $yaml_loader = new YamlFileLoader($container);
 1259     foreach ($this->serviceYamls['app'] as $filename) {
 1260       $yaml_loader->load($filename);
 1261     }
 1262     foreach ($this->serviceProviders['app'] as $provider) {
 1263       if ($provider instanceof ServiceProviderInterface) {
 1264         $provider->register($container);
 1265       }
 1266     }
 1267     // Register site-specific service overrides.
 1268     foreach ($this->serviceYamls['site'] as $filename) {
 1269       $yaml_loader->load($filename);
 1270     }
 1271     foreach ($this->serviceProviders['site'] as $provider) {
 1272       if ($provider instanceof ServiceProviderInterface) {
 1273         $provider->register($container);
 1274       }
 1275     }
 1276 
 1277     // Identify all services whose instances should be persisted when rebuilding
 1278     // the container during the lifetime of the kernel (e.g., during a kernel
 1279     // reboot). Include synthetic services, because by definition, they cannot
 1280     // be automatically reinstantiated. Also include services tagged to persist.
 1281     $persist_ids = [];
 1282     foreach ($container->getDefinitions() as $id => $definition) {
 1283       // It does not make sense to persist the container itself, exclude it.
 1284       if ($id !== 'service_container' && ($definition->isSynthetic() || $definition->getTag('persist'))) {
 1285         $persist_ids[] = $id;
 1286       }
 1287     }
 1288     $container->setParameter('persist_ids', $persist_ids);
 1289 
 1290     $container->setParameter('app.root', $this->getAppRoot());
 1291     $container->setParameter('site.path', $this->getSitePath());
 1292 
 1293     $container->compile();
 1294     return $container;
 1295   }
 1296 
 1297   /**
 1298    * Registers all service providers to the kernel.
 1299    *
 1300    * @throws \LogicException
 1301    */
 1302   protected function initializeServiceProviders() {
 1303     $this->discoverServiceProviders();
 1304     $this->serviceProviders = [
 1305       'app' => [],
 1306       'site' => [],
 1307     ];
 1308     foreach ($this->serviceProviderClasses as $origin => $classes) {
 1309       foreach ($classes as $name => $class) {
 1310         if (!is_object($class)) {
 1311           $this->serviceProviders[$origin][$name] = new $class();
 1312         }
 1313         else {
 1314           $this->serviceProviders[$origin][$name] = $class;
 1315         }
 1316       }
 1317     }
 1318   }
 1319 
 1320   /**
 1321    * Gets a new ContainerBuilder instance used to build the service container.
 1322    *
 1323    * @return \Drupal\Core\DependencyInjection\ContainerBuilder
 1324    */
 1325   protected function getContainerBuilder() {
 1326     return new ContainerBuilder(new ParameterBag($this->getKernelParameters()));
 1327   }
 1328 
 1329   /**
 1330    * Stores the container definition in a cache.
 1331    *
 1332    * @param array $container_definition
 1333    *   The container definition to cache.
 1334    *
 1335    * @return bool
 1336    *   TRUE if the container was successfully cached.
 1337    */
 1338   protected function cacheDrupalContainer(array $container_definition) {
 1339     $saved = TRUE;
 1340     try {
 1341       $this->bootstrapContainer->get('cache.container')->set($this->getContainerCacheKey(), $container_definition);
 1342     }
 1343     catch (\Exception $e) {
 1344       // There is no way to get from the Cache API if the cache set was
 1345       // successful or not, hence an Exception is caught and the caller informed
 1346       // about the error condition.
 1347       $saved = FALSE;
 1348     }
 1349 
 1350     return $saved;
 1351   }
 1352 
 1353   /**
 1354    * Gets a http kernel from the container
 1355    *
 1356    * @return \Symfony\Component\HttpKernel\HttpKernelInterface
 1357    */
 1358   protected function getHttpKernel() {
 1359     return $this->container->get('http_kernel');
 1360   }
 1361 
 1362   /**
 1363    * Returns the active configuration storage to use during building the container.
 1364    *
 1365    * @return \Drupal\Core\Config\StorageInterface
 1366    */
 1367   protected function getConfigStorage() {
 1368     if (!isset($this->configStorage)) {
 1369       // The active configuration storage may not exist yet; e.g., in the early
 1370       // installer so if an exception is thrown use a NullStorage.
 1371       try {
 1372         $this->configStorage = BootstrapConfigStorageFactory::get($this->classLoader);
 1373       }
 1374       catch (\Exception $e) {
 1375         $this->configStorage = new NullStorage();
 1376       }
 1377     }
 1378     return $this->configStorage;
 1379   }
 1380 
 1381   /**
 1382    * Returns an array of Extension class parameters for all enabled modules.
 1383    *
 1384    * @return array
 1385    */
 1386   protected function getModulesParameter() {
 1387     $extensions = [];
 1388     foreach ($this->moduleList as $name => $weight) {
 1389       if ($data = $this->moduleData($name)) {
 1390         $extensions[$name] = [
 1391           'type' => $data->getType(),
 1392           'pathname' => $data->getPathname(),
 1393           'filename' => $data->getExtensionFilename(),
 1394         ];
 1395       }
 1396     }
 1397     return $extensions;
 1398   }
 1399 
 1400   /**
 1401    * Gets the file name for each enabled module.
 1402    *
 1403    * @return array
 1404    *   Array where each key is a module name, and each value is a path to the
 1405    *   respective *.info.yml file.
 1406    */
 1407   protected function getModuleFileNames() {
 1408     $filenames = [];
 1409     foreach ($this->moduleList as $module => $weight) {
 1410       if ($data = $this->moduleData($module)) {
 1411         $filenames[$module] = $data->getPathname();
 1412       }
 1413     }
 1414     return $filenames;
 1415   }
 1416 
 1417   /**
 1418    * Gets the PSR-4 base directories for module namespaces.
 1419    *
 1420    * @param string[] $module_file_names
 1421    *   Array where each key is a module name, and each value is a path to the
 1422    *   respective *.info.yml file.
 1423    *
 1424    * @return string[]
 1425    *   Array where each key is a module namespace like 'Drupal\system', and each
 1426    *   value is the PSR-4 base directory associated with the module namespace.
 1427    */
 1428   protected function getModuleNamespacesPsr4($module_file_names) {
 1429     $namespaces = [];
 1430     foreach ($module_file_names as $module => $filename) {
 1431       $namespaces["Drupal\\$module"] = dirname($filename) . '/src';
 1432     }
 1433     return $namespaces;
 1434   }
 1435 
 1436   /**
 1437    * Registers a list of namespaces with PSR-4 directories for class loading.
 1438    *
 1439    * @param array $namespaces
 1440    *   Array where each key is a namespace like 'Drupal\system', and each value
 1441    *   is either a PSR-4 base directory, or an array of PSR-4 base directories
 1442    *   associated with this namespace.
 1443    * @param object $class_loader
 1444    *   The class loader. Normally \Composer\Autoload\ClassLoader, as included by
 1445    *   the front controller, but may also be decorated; e.g.,
 1446    *   \Symfony\Component\ClassLoader\ApcClassLoader.
 1447    */
 1448   protected function classLoaderAddMultiplePsr4(array $namespaces = [], $class_loader = NULL) {
 1449     if ($class_loader === NULL) {
 1450       $class_loader = $this->classLoader;
 1451     }
 1452     foreach ($namespaces as $prefix => $paths) {
 1453       if (is_array($paths)) {
 1454         foreach ($paths as $key => $value) {
 1455           $paths[$key] = $this->root . '/' . $value;
 1456         }
 1457       }
 1458       elseif (is_string($paths)) {
 1459         $paths = $this->root . '/' . $paths;
 1460       }
 1461       $class_loader->addPsr4($prefix . '\\', $paths);
 1462     }
 1463   }
 1464 
 1465   /**
 1466    * Validates a hostname length.
 1467    *
 1468    * @param string $host
 1469    *   A hostname.
 1470    *
 1471    * @return bool
 1472    *   TRUE if the length is appropriate, or FALSE otherwise.
 1473    */
 1474   protected static function validateHostnameLength($host) {
 1475     // Limit the length of the host name to 1000 bytes to prevent DoS attacks
 1476     // with long host names.
 1477     return strlen($host) <= 1000
 1478     // Limit the number of subdomains and port separators to prevent DoS attacks
 1479     // in findSitePath().
 1480     && substr_count($host, '.') <= 100
 1481     && substr_count($host, ':') <= 100;
 1482   }
 1483 
 1484   /**
 1485    * Validates the hostname supplied from the HTTP request.
 1486    *
 1487    * @param \Symfony\Component\HttpFoundation\Request $request
 1488    *   The request object
 1489    *
 1490    * @return bool
 1491    *   TRUE if the hostname is valid, or FALSE otherwise.
 1492    */
 1493   public static function validateHostname(Request $request) {
 1494     // $request->getHost() can throw an UnexpectedValueException if it
 1495     // detects a bad hostname, but it does not validate the length.
 1496     try {
 1497       $http_host = $request->getHost();
 1498     }
 1499     catch (\UnexpectedValueException $e) {
 1500       return FALSE;
 1501     }
 1502 
 1503     if (static::validateHostnameLength($http_host) === FALSE) {
 1504       return FALSE;
 1505     }
 1506 
 1507     return TRUE;
 1508   }
 1509 
 1510   /**
 1511    * Sets up the lists of trusted HTTP Host headers.
 1512    *
 1513    * Since the HTTP Host header can be set by the user making the request, it
 1514    * is possible to create an attack vectors against a site by overriding this.
 1515    * Symfony provides a mechanism for creating a list of trusted Host values.
 1516    *
 1517    * Host patterns (as regular expressions) can be configured through
 1518    * settings.php for multisite installations, sites using ServerAlias without
 1519    * canonical redirection, or configurations where the site responds to default
 1520    * requests. For example,
 1521    *
 1522    * @code
 1523    * $settings['trusted_host_patterns'] = array(
 1524    *   '^example\.com$',
 1525    *   '^*.example\.com$',
 1526    * );
 1527    * @endcode
 1528    *
 1529    * @param \Symfony\Component\HttpFoundation\Request $request
 1530    *   The request object.
 1531    * @param array $host_patterns
 1532    *   The array of trusted host patterns.
 1533    *
 1534    * @return bool
 1535    *   TRUE if the Host header is trusted, FALSE otherwise.
 1536    *
 1537    * @see https://www.drupal.org/docs/8/install/trusted-host-settings
 1538    * @see \Drupal\Core\Http\TrustedHostsRequestFactory
 1539    */
 1540   protected static function setupTrustedHosts(Request $request, $host_patterns) {
 1541     $request->setTrustedHosts($host_patterns);
 1542 
 1543     // Get the host, which will validate the current request.
 1544     try {
 1545       $host = $request->getHost();
 1546 
 1547       // Fake requests created through Request::create() without passing in the
 1548       // server variables from the main request have a default host of
 1549       // 'localhost'. If 'localhost' does not match any of the trusted host
 1550       // patterns these fake requests would fail the host verification. Instead,
 1551       // TrustedHostsRequestFactory makes sure to pass in the server variables
 1552       // from the main request.
 1553       $request_factory = new TrustedHostsRequestFactory($host);
 1554       Request::setFactory([$request_factory, 'createRequest']);
 1555 
 1556     }
 1557     catch (\UnexpectedValueException $e) {
 1558       return FALSE;
 1559     }
 1560 
 1561     return TRUE;
 1562   }
 1563 
 1564   /**
 1565    * Add service files.
 1566    *
 1567    * @param string[] $service_yamls
 1568    *   A list of service files.
 1569    */
 1570   protected function addServiceFiles(array $service_yamls) {
 1571     $this->serviceYamls['site'] = array_filter($service_yamls, 'file_exists');
 1572   }
 1573 
 1574   /**
 1575    * Gets the active install profile.
 1576    *
 1577    * @return string|null
 1578    *   The name of the any active install profile or distribution.
 1579    */
 1580   protected function getInstallProfile() {
 1581     $config = $this->getConfigStorage()->read('core.extension');
 1582 
 1583     // Normalize an empty string to a NULL value.
 1584     return $config['profile'] ?? NULL;
 1585   }
 1586 
 1587 }