From f498d2a4959e743fe6f9fb44e38488fcc0643efb Mon Sep 17 00:00:00 2001
From: Mark Carver <mark.carver@me.com>
Date: Sat, 24 Feb 2018 15:42:07 -0600
Subject: [PATCH] WIP

Signed-off-by: Mark Carver <mark.carver@me.com>
---
 .travis.yml                             |   5 +-
 composer.json                           |  61 +++-
 core.services.yml                       |   1 +
 patches/Drupal_Core_Site_Settings.patch |  31 ++
 service_container.info                  |   3 +-
 service_container.module                |  78 ++---
 src/Drupal7Kernel.php                   | 548 ++++++++++++++++++++++++++++++++
 7 files changed, 661 insertions(+), 66 deletions(-)
 create mode 100644 core.services.yml
 create mode 100644 patches/Drupal_Core_Site_Settings.patch
 create mode 100644 src/Drupal7Kernel.php

diff --git a/.travis.yml b/.travis.yml
index 7578bbf..60841c2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,6 @@ language: php
 sudo: false
 
 php:
-  - 5.3
-  - 5.4
   - 5.5
   - 5.6
   - 7
@@ -21,8 +19,7 @@ php:
 branches:
   only:
     - "7.x-1.x"
-    - "8.x-1.x"
-    
+
 cache:
   apt: true
   directories:
diff --git a/composer.json b/composer.json
index fb8e0c6..d9b795a 100644
--- a/composer.json
+++ b/composer.json
@@ -1,30 +1,57 @@
 {
-  "name": "lionsad/service_container",
+  "name": "drupal/service_container",
   "description": "Service Container based on CTools plugins with Symfony Integration",
   "type": "drupal-module",
   "homepage": "https://www.drupal.org/project/service_container",
   "license": "GPL-2.0+",
-  "minimum-stability": "dev",
-  "prefer-stable": true,
   "authors": [
-    { "name": "Fabian Franz", "email": "fabian@lionsad.de" }
+    {
+      "name": "Fabian Franz",
+      "email": "fabian@lionsad.de",
+      "homepage": "https://www.drupal.org/u/Fabianx",
+      "role": "Maintainer"
+    },
+    {
+      "name": "Mark Carver",
+      "email": "mark.carver@me.com",
+      "homepage": "https://www.drupal.org/u/markcarver",
+      "role": "Co-Maintainer"
+    },
+    {
+      "name": "Daniel Wehner",
+      "homepage": "https://www.drupal.org/u/dawehner",
+      "role": "Co-Maintainer"
+    },
+    {
+      "name": "Pol Dellaiera",
+      "homepage": "https://www.drupal.org/u/pol",
+      "role": "Co-Maintainer"
+    }
   ],
-  "require": {
-    "php": ">=5.3.10"
-  },
-  "autoload": {
-    "psr-0": {
-      "Drupal\\Component\\": "lib/",
-      "Drupal\\Core\\": "lib/",
-      "ServiceContainer": "lib/",
-      "Drupal": "lib/",
-      "Symfony\\Component\\DependencyInjection": "lib/",
-      "Psr": "lib/"
+  "minimum-stability": "dev",
+  "prefer-stable": true,
+  "extra": {
+    "installer-paths": {
+      "COMPOSER_VENDOR_DIR/drupal/core": ["type:drupal-core"],
+      "DRUPAL_ROOT/sites/all/modules/contrib/{$name}": ["type:drupal-module"],
+      "DRUPAL_ROOT/sites/all/profiles/contrib/{$name}": ["type:drupal-profile"],
+      "DRUPAL_ROOT/sites/all/themes/contrib/{$name}": ["type:drupal-theme"],
+      "DRUPAL_ROOT/sites/all/drush/{$name}": ["type:drupal-drush"],
+      "DRUPAL_ROOT/sites/all/modules/custom/{$name}": ["type:drupal-custom-module"],
+      "DRUPAL_ROOT/sites/all/themes/custom/{$name}": ["type:drupal-custom-theme"]
     },
-    "psr-4": {
-      "Drupal\\service_container\\": "src/"
+    "patches": {
+      "drupal/core": {
+        "Drupal\\Core\\Site\\Settings": "./patches/Drupal_Core_Site_Settings.patch"
+      }
     }
   },
+  "require": {
+    "php": ">=5.5.9",
+    "composer/installers": "^1.0.24",
+    "cweagans/composer-patches": "^1.6",
+    "drupal/core": "~8.4.5"
+  },
   "autoload-dev": {
     "psr-4": {
       "Drupal\\service_container\\Tests\\": "tests/src/"
diff --git a/core.services.yml b/core.services.yml
new file mode 100644
index 0000000..0baad47
--- /dev/null
+++ b/core.services.yml
@@ -0,0 +1 @@
+services:
diff --git a/patches/Drupal_Core_Site_Settings.patch b/patches/Drupal_Core_Site_Settings.patch
new file mode 100644
index 0000000..68dec24
--- /dev/null
+++ b/patches/Drupal_Core_Site_Settings.patch
@@ -0,0 +1,31 @@
+diff --git a/lib/Drupal/Core/Site/Settings.php b/lib/Drupal/Core/Site/Settings.php
+index bdd2609a7c..808dabc6a7 100644
+--- a/lib/Drupal/Core/Site/Settings.php
++++ b/lib/Drupal/Core/Site/Settings.php
+@@ -3,6 +3,7 @@
+ namespace Drupal\Core\Site;
+ 
+ use Drupal\Component\Utility\Crypt;
++use Drupal\Component\Utility\NestedArray;
+ use Drupal\Core\Database\Database;
+ 
+ /**
+@@ -116,12 +117,17 @@ public static function initialize($app_root, $site_path, &$class_loader) {
+     global $config_directories, $config;
+     $settings = [];
+     $config = [];
+-    $databases = [];
++
++    // Also specify Drupal 7 globals.
++    global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url;
+ 
+     if (is_readable($app_root . '/' . $site_path . '/settings.php')) {
+       require $app_root . '/' . $site_path . '/settings.php';
+     }
+ 
++    // Merge in Drupal 7 configuration into settings.
++    $settings = NestedArray::mergeDeep($conf, $settings);
++
+     // Initialize Database.
+     Database::setMultipleConnectionInfo($databases);
+ 
diff --git a/service_container.info b/service_container.info
index 901b14f..1c344ba 100644
--- a/service_container.info
+++ b/service_container.info
@@ -2,10 +2,11 @@ name = Service Container
 description = A light-weight service container based on CTools plugins.
 package = Utility
 core = 7.x
-php = 5.6
+php = 5.5.9
 
 ; Hard dependencies.
 dependencies[] = any
+dependencies[] = composer_manager (>= 7.x-1.8)
 dependencies[] = ctools
 
 ; Require one of the following autoload contrib dependencies.
diff --git a/service_container.module b/service_container.module
index 4d18c77..2d80360 100644
--- a/service_container.module
+++ b/service_container.module
@@ -1,28 +1,40 @@
 <?php
+
 /**
  * @file
- * Main module file for the service_container module.
+ * Service Container module.
  */
 
-// -----------------------------------------------------------------------
-// Core Hooks
+use Drupal\service_container\Drupal7Kernel;
+use Symfony\Component\HttpFoundation\Request;
+
+function service_container_kernel() {
+  static $kernel;
+
+  if (!isset($kernel) && class_exists('\Drupal\service_container\Drupal7Kernel')) {
+    // Use require, not require_once (which returns TRUE if already loaded).
+    $vendor_dir = composer_manager_vendor_dir();
+    $autoloader = require "$vendor_dir/autoload.php";
+    $kernel = Drupal7Kernel::createFromRequest(Request::createFromGlobals(), $autoloader, 'prod', TRUE, DRUPAL_ROOT, $vendor_dir);
+  }
+
+  return $kernel;
+}
 
 /**
- * Implements hook_stream_wrappers_alter().
+ * Implements hook_boot().
  */
-function service_container_stream_wrappers_alter(&$wrappers) {
-  if (class_exists('ServiceContainer')) {
-    ServiceContainer::init();
-  }
+function service_container_boot() {
+  service_container_kernel();
 }
 
 /**
  * Implements hook_modules_enabled().
  */
 function service_container_modules_enabled() {
-  if (class_exists('ServiceContainer')) {
-    ServiceContainer::reset();
-    ServiceContainer::init();
+  // Rebuild the container.
+  if ($kernel = service_container_kernel()) {
+    $kernel->rebuildContainer();
   }
 }
 
@@ -30,39 +42,17 @@ function service_container_modules_enabled() {
  * Implements hook_module_implements_alter().
  */
 function service_container_module_implements_alter(&$implementations, $hook) {
-  // Moves our hook_init() implementation to occur first so that we
-  // can initialize the container.
-  if ($hook == 'stream_wrappers_alter') {
-    $group = $implementations['service_container'];
+  // Moves this module's hook_boot() implementation and composer_manager's to
+  // the beginning so it is invoked before other modules implementing the same
+  // hook.
+  if ($hook === 'boot') {
+    $composer_manager = $implementations['composer_manager'];
+    $service_container = $implementations['service_container'];
+    unset($implementations['composer_manager']);
     unset($implementations['service_container']);
-    $implementations = array('service_container' => $group) + $implementations;
-  }
-}
-
-// -----------------------------------------------------------------------
-// Contrib Hooks
-
-/**
- * Implements hook_ctools_plugin_type().
- */
-function service_container_ctools_plugin_type() {
-  $items['ServiceProvider'] = array(
-    'cache' => FALSE,
-  );
-
-  return $items;
-}
-
-/**
- * Implements hook_ctools_plugin_directory().
- */
-function service_container_ctools_plugin_directory($owner, $plugin_type) {
-  if ($owner == 'service_container') {
-    return 'src/ServiceContainer/' . $plugin_type;
+    $implementations = [
+        'composer_manager' => $composer_manager,
+        'service_container' => $service_container,
+      ] + $implementations;
   }
-
-  return NULL;
 }
-
-// -----------------------------------------------------------------------
-// Public API
diff --git a/src/Drupal7Kernel.php b/src/Drupal7Kernel.php
new file mode 100644
index 0000000..8196191
--- /dev/null
+++ b/src/Drupal7Kernel.php
@@ -0,0 +1,548 @@
+<?php
+
+namespace Drupal\service_container;
+
+use Drupal\Component\FileCache\FileCacheFactory;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DependencyInjection\ServiceModifierInterface;
+use Drupal\Core\DependencyInjection\ServiceProviderInterface;
+use Drupal\Core\DependencyInjection\YamlFileLoader;
+use Drupal\Core\DrupalKernel;
+use Drupal\Core\DrupalKernelInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\ClassLoader\ApcClassLoader;
+use Symfony\Component\ClassLoader\WinCacheClassLoader;
+use Symfony\Component\ClassLoader\XcacheClassLoader;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+use Symfony\Component\HttpKernel\TerminableInterface;
+
+/**
+ * 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 Drupal7Kernel extends DrupalKernel implements DrupalKernelInterface, TerminableInterface {
+
+  protected $vendorDir;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct($environment, $class_loader, $allow_dumping = TRUE, $app_root = NULL, $vendor_dir = NULL) {
+    parent::__construct($environment, $class_loader, $allow_dumping, $app_root);
+    $this->vendorDir = $vendor_dir;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE, $app_root = NULL, $vendor_dir = NULL) {
+    $kernel = new static($environment, $class_loader, $allow_dumping, $app_root, $vendor_dir);
+    static::bootEnvironment($app_root);
+    $kernel->initializeSettings($request);
+    $kernel->boot();
+    return $kernel;
+  }
+
+  public function setVendorDir($vendor_dir) {
+    $this->vendorDir = $vendor_dir;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static function guessApplicationRoot() {
+    return DRUPAL_ROOT;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  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'])) {
+      // @todo Use extension_loaded('apcu') for non-testbot
+      //  https://www.drupal.org/node/2447753.
+      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.
+    $this->initializeContainer();
+
+    $this->booted = TRUE;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function shutdown() {
+    if (FALSE === $this->booted) {
+      return;
+    }
+    $this->booted = FALSE;
+    $this->container = NULL;
+    $this->moduleList = NULL;
+    $this->moduleData = [];
+  }
+
+  /**
+   * {@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() {
+    // Intentionally left blank, Drupal 7 has already bootstrapped.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function discoverServiceProviders() {
+    $this->serviceYamls = [
+      'app' => [],
+      'site' => [],
+    ];
+    $this->serviceProviderClasses = [
+      'app' => [],
+      'site' => [],
+    ];
+    $this->serviceYamls['app']['core'] = drupal_get_path('module', 'service_container') . '/core.services.yml';
+    $this->serviceProviderClasses['app']['core'] = 'Drupal\Core\CoreServiceProvider';
+
+    // Retrieve enabled modules and register their namespaces.
+    if (!isset($this->moduleList)) {
+      $extensions = $this->getConfigStorage()->read('core.extension');
+      $this->moduleList = isset($extensions['module']) ? $extensions['module'] : [];
+    }
+    $module_filenames = $this->getModuleFileNames();
+    $this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($module_filenames));
+
+    // Load each module's serviceProvider class.
+    foreach ($module_filenames as $module => $filename) {
+      $camelized = ContainerBuilder::camelize($module);
+      $name = "{$camelized}ServiceProvider";
+      $class = "Drupal\\{$module}\\{$name}";
+      if (class_exists($class)) {
+        $this->serviceProviderClasses['app'][$module] = $class;
+      }
+      $filename = dirname($filename) . "/$module.services.yml";
+      if (file_exists($filename)) {
+        $this->serviceYamls['app'][$module] = $filename;
+      }
+    }
+
+    // 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;
+        }
+      }
+    }
+    $this->addServiceFiles(Settings::get('container_yamls', []));
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @deprecated This method is not supported in Drupal 7
+   */
+  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+    throw new \Exception('This method is not supported in Drupal 7');
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @deprecated This method is not supported in Drupal 7
+   */
+  public function prepareLegacyRequest(Request $request) {
+    throw new \Exception('This method is not supported in Drupal 7');
+  }
+
+  /**
+   * Returns the container cache key based on the environment.
+   *
+   * 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.
+   *
+   * @return string
+   *   The cache key used for the service container.
+   */
+  protected function getContainerCacheKey() {
+    $parts = ['service_container', $this->environment, \Drupal::VERSION, Settings::get('deployment_identifier'), PHP_OS, serialize(Settings::get('container_yamls'))];
+    return implode(':', $parts);
+  }
+
+  /**
+   * Returns the kernel parameters.
+   *
+   * @return array An array of kernel parameters
+   */
+  protected function getKernelParameters() {
+    return [
+      'kernel.environment' => $this->environment,
+    ];
+  }
+
+  /**
+   * Initializes the service container.
+   *
+   * @return \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  protected function initializeContainer() {
+    $this->containerNeedsDumping = FALSE;
+    $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();
+      }
+
+      // 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();
+        }
+        unset($session);
+      }
+    }
+
+    // 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)) {
+      // Building the container creates 1000s of objects. Garbage collection of
+      // these objects is expensive. This appears to be causing random
+      // segmentation faults in PHP 5.6 due to
+      // https://bugs.php.net/bug.php?id=72286. Once the container is rebuilt,
+      // garbage collection is re-enabled.
+      $disable_gc = version_compare(PHP_VERSION, '7', '<') && gc_enabled();
+      if ($disable_gc) {
+        gc_collect_cycles();
+        gc_disable();
+      }
+      $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();
+      }
+      // If garbage collection was disabled prior to rebuilding container,
+      // re-enable it.
+      if ($disable_gc) {
+        gc_enable();
+      }
+    }
+
+    // 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;
+    if ($session_started) {
+      $this->container->get('session')->start();
+    }
+
+    // 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()) {
+        $subrequest = TRUE;
+        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);
+
+    // Allow other parts of the codebase to react on container initialization in
+    // subrequest.
+    if (!empty($subrequest)) {
+      $this->container->get('event_dispatcher')->dispatch(self::CONTAINER_INITIALIZE_SUBREQUEST_FINISHED);
+    }
+
+    // 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;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function bootEnvironment($app_root = NULL) {
+    // Drupal 7 is already bootstrapped, ignore.
+    static::$isEnvironmentInitialized = TRUE;
+  }
+
+  /**
+   * Locate site path and initialize settings singleton.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   *   In case the host name in the request is not trusted.
+   */
+  protected function initializeSettings(Request $request) {
+    $site_path = static::findSitePath($request);
+    $this->setSitePath($site_path);
+    $class_loader_class = get_class($this->classLoader);
+    Settings::initialize($this->root, $site_path, $this->classLoader);
+
+    // Initialize our list of trusted HTTP Host headers to protect against
+    // header attacks.
+    $host_patterns = Settings::get('trusted_host_patterns', []);
+    if (PHP_SAPI !== 'cli' && !empty($host_patterns)) {
+      if (static::setupTrustedHosts($request, $host_patterns) === FALSE) {
+        throw new BadRequestHttpException('The provided host name is not valid for this server.');
+      }
+    }
+
+    // If the class loader is still the same, possibly
+    // upgrade to an optimized class loader.
+    if ($class_loader_class == get_class($this->classLoader)
+      && Settings::get('class_loader_auto_detect', TRUE)) {
+      $prefix = Settings::getApcuPrefix('class_loader', $this->root);
+      $loader = NULL;
+
+      // We autodetect one of the following three optimized classloaders, if
+      // their underlying extension exists.
+      if (function_exists('apcu_fetch')) {
+        $loader = new ApcClassLoader($prefix, $this->classLoader);
+      }
+      elseif (extension_loaded('wincache')) {
+        $loader = new WinCacheClassLoader($prefix, $this->classLoader);
+      }
+      elseif (extension_loaded('xcache')) {
+        $loader = new XcacheClassLoader($prefix, $this->classLoader);
+      }
+      if (!empty($loader)) {
+        $this->classLoader->unregister();
+        // The optimized classloader might be persistent and store cache misses.
+        // For example, once a cache miss is stored in APCu clearing it on a
+        // specific web-head will not clear any other web-heads. Therefore
+        // fallback to the composer class loader that only statically caches
+        // misses.
+        $old_loader = $this->classLoader;
+        $this->classLoader = $loader;
+        // Our class loaders are preprended to ensure they come first like the
+        // class loader they are replacing.
+        $old_loader->register(TRUE);
+        $loader->register(TRUE);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @deprecated This method is not supported in Drupal 7.
+   */
+  protected function initializeRequestGlobals(Request $request) {
+    throw new \Exception('This method is not supported in Drupal 7');
+  }
+
+  /**
+   * Compiles a new service container.
+   *
+   * @return \Drupal\Core\DependencyInjection\ContainerBuilder The compiled service container
+   */
+  protected function compileContainer() {
+    // We are forcing a container build so it is reasonable to assume that the
+    // calling method knows something about the system has changed requiring the
+    // container to be dumped to the filesystem.
+    if ($this->allowDumping) {
+      $this->containerNeedsDumping = TRUE;
+    }
+
+    $this->initializeServiceProviders();
+    $container = $this->getContainerBuilder();
+    $container->set('kernel', $this);
+    $container->setParameter('container.modules', $this->getModulesParameter());
+    $container->setParameter('install_profile', $this->getInstallProfile());
+
+    // Get a list of namespaces and put it onto the container.
+    $namespaces = $this->getModuleNamespacesPsr4($this->getModuleFileNames());
+    // Add all components in \Drupal\Core and \Drupal\Component that have one of
+    // the following directories:
+    // - Element
+    // - Entity
+    // - Plugin
+    foreach (['Core', 'Component'] as $parent_directory) {
+      $path = 'core/lib/Drupal/' . $parent_directory;
+      $parent_namespace = 'Drupal\\' . $parent_directory;
+      foreach (new \DirectoryIterator($this->root . '/' . $path) as $component) {
+        /** @var $component \DirectoryIterator */
+        $pathname = $component->getPathname();
+        if (!$component->isDot() && $component->isDir() && (
+            is_dir($pathname . '/Plugin') ||
+            is_dir($pathname . '/Entity') ||
+            is_dir($pathname . '/Element')
+          )) {
+          $namespaces[$parent_namespace . '\\' . $component->getFilename()] = $path . '/' . $component->getFilename();
+        }
+      }
+    }
+    $container->setParameter('container.namespaces', $namespaces);
+
+    // Store the default language values on the container. This is so that the
+    // default language can be configured using the configuration factory. This
+    // avoids the circular dependencies that would created by
+    // \Drupal\language\LanguageServiceProvider::alter() and allows the default
+    // language to not be English in the installer.
+    $default_language_values = Language::$defaultValues;
+    if ($system = $this->getConfigStorage()->read('system.site')) {
+      if ($default_language_values['id'] != $system['langcode']) {
+        $default_language_values = ['id' => $system['langcode']];
+      }
+    }
+    $container->setParameter('language.default_values', $default_language_values);
+
+    // Register synthetic services.
+    $container->register('class_loader')->setSynthetic(TRUE);
+    $container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE);
+    $container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE);
+
+    // Register application services.
+    $yaml_loader = new YamlFileLoader($container);
+    foreach ($this->serviceYamls['app'] as $filename) {
+      $yaml_loader->load($filename);
+    }
+    foreach ($this->serviceProviders['app'] as $provider) {
+      if ($provider instanceof ServiceProviderInterface) {
+        $provider->register($container);
+      }
+    }
+    // Register site-specific service overrides.
+    foreach ($this->serviceYamls['site'] as $filename) {
+      $yaml_loader->load($filename);
+    }
+    foreach ($this->serviceProviders['site'] as $provider) {
+      if ($provider instanceof ServiceProviderInterface) {
+        $provider->register($container);
+      }
+    }
+
+    // Identify all services whose instances should be persisted when rebuilding
+    // the container during the lifetime of the kernel (e.g., during a kernel
+    // reboot). Include synthetic services, because by definition, they cannot
+    // be automatically reinstantiated. Also include services tagged to persist.
+    $persist_ids = [];
+    foreach ($container->getDefinitions() as $id => $definition) {
+      // It does not make sense to persist the container itself, exclude it.
+      if ($id !== 'service_container' && ($definition->isSynthetic() || $definition->getTag('persist'))) {
+        $persist_ids[] = $id;
+      }
+    }
+    $container->setParameter('persist_ids', $persist_ids);
+
+    $container->compile();
+    return $container;
+  }
+
+}
-- 
2.15.1

