diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index f6c69a5..2c240f0 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -2,10 +2,10 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\Database\Database; +use Drupal\Core\DependencyInjection\ContainerBuilder; use Symfony\Component\ClassLoader\UniversalClassLoader; use Symfony\Component\ClassLoader\ApcUniversalClassLoader; use Symfony\Component\DependencyInjection\Container; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Exception\RuntimeException as DependencyInjectionRuntimeException; use Symfony\Component\HttpFoundation\Request; @@ -2397,6 +2397,48 @@ function drupal_get_bootstrap_phase() { } /** + * Returns a minimal service container to boot or rebuild the Drupal kernel. + * + * @return Symfony\Component\DependencyInjection\Container + * A service container with the bare essentials needed to boot for rebuild + * DrupalKernel. + * + * @see Drupal\Core\DrupalKernel + */ +function drupal_bootstrap_container() { + $container = new ContainerBuilder(); + + // Classloader. + $container + ->set('classloader', drupal_classloader()); + + // Configuration system. + $container + ->register('config.storage', 'Drupal\Core\Config\FileStorage') + ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); + $container + ->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); + $container + ->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher') + ->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf'))); + $container + ->register('config.factory', 'Drupal\Core\Config\ConfigFactory') + ->addArgument(new Reference('config.storage')) + ->addArgument(new Reference('dispatcher')); + + // PHP Storage. + $container + ->register('php_storage.service_container', 'Drupal\Component\PhpStorage\MTimeProtectedFileStorage') + ->addArgument(array( + 'bin' => 'service_container', + 'directory' => DRUPAL_ROOT . '/' . conf_path() . '/files/php', + 'secret' => $GLOBALS['drupal_hash_salt'], + )); + + return $container; +} + +/** * Retrieves the Drupal Container to standardize object construction. * * On a normal page request the container is built by the kernel and passed in diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 072e109..96796ed 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -7,16 +7,15 @@ namespace Drupal\Core; +use Drupal\Component\PhpStorage\PhpStorageInterface; use Drupal\Core\Cache\CacheBackendInterface; -use Symfony\Component\ClassLoader\UniversalClassLoader; -use Drupal\Core\Config\FileStorage; use Drupal\Core\CoreBundle; -use Drupal\Component\PhpStorage\PhpStorageInterface; -use Symfony\Component\HttpKernel\Kernel; use Drupal\Core\DependencyInjection\ContainerBuilder; +use Symfony\Component\ClassLoader\UniversalClassLoader; use Symfony\Component\Config\Loader\LoaderInterface; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\HttpKernel\Kernel; /** * The DrupalKernel class is the core of Drupal itself. @@ -30,6 +29,8 @@ */ class DrupalKernel extends Kernel implements DrupalKernelInterface { + protected $baseContainer; + /** * Holds the list of enabled modules. * @@ -90,20 +91,17 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface { * Boolean indicating whether we are in debug mode. Used by * Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use * this value currently. Pass TRUE. - * @param \Symfony\Component\ClassLoader\UniversalClassLoader $class_loader - * (optional) The classloader is only used if $storage is not given or - * the load from storage fails and a container rebuild is required. In - * this case, the loaded modules will be registered with this loader in - * order to be able to find the module bundles. - * @param \Drupal\Component\PhpStorage\PhpStorageInterface $storage - * (optional) An object handling the load and save of the compiled - * container. If not specified, the container will neither be stored to - * disk nor read from there. + * @param \Symfony\Component\DepedencyInjection\ContainerBuilder $base_container + * A minimal service container containing the required services to boot or + * rebuild DrupalKernel. */ - public function __construct($environment, $debug, UniversalClassLoader $class_loader, PhpStorageInterface $storage = NULL) { + public function __construct($environment, $debug, ContainerBuilder $base_container) { parent::__construct($environment, $debug); - $this->storage = $storage; - $this->classLoader = $class_loader; + $this->baseContainer = $base_container; + + $this->storage = $this->baseContainer->get('php_storage.service_container'); + $this->classLoader = $this->baseContainer->get('classloader'); + $this->config = $this->baseContainer->get('config.factory'); } /** @@ -135,9 +133,8 @@ public function registerBundles() { new CoreBundle(), ); if (!isset($this->moduleList)) { - $storage = new FileStorage(config_get_config_directory()); - $module_list = $storage->read('system.module'); - $this->moduleList = isset($module_list['enabled']) ? $module_list['enabled'] : array(); + $module_list = $this->config->get('system.module')->load()->get('enabled'); + $this->moduleList = is_array($module_list) ? $module_list : array(); } $namespaces = $this->classLoader->getNamespaces(); @@ -177,10 +174,11 @@ protected function moduleData($module) { $profiles_scanner = new SystemListing(); $all_profiles = $profiles_scanner->scan('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.profile$/', 'profiles'); $profiles = array_keys(array_intersect_key($this->moduleList, $all_profiles)); - $storage = new FileStorage(config_get_config_directory()); + // If a module is within a profile directory but specifies another // profile for testing, it needs to be found in the parent profile. - if (($parent_profile_config = $storage->read('simpletest.settings')) && isset($parent_profile_config['parent_profile']) && $parent_profile_config['parent_profile'] != $profiles[0]) { + $parent_profile = $this->config->get('simpletest.settings')->load()->get('parent_profile'); + if ($parent_profile && $parent_profile_config['parent_profile'] != $profiles[0]) { // In case both profile directories contain the same extension, the // actual profile always has precedence. array_unshift($profiles, $parent_profile_config['parent_profile']); @@ -204,7 +202,6 @@ public function updateModules(array $module_list, array $module_paths = array()) // list will take effect when boot() is called. If we have already booted, // then reboot in order to refresh the bundle list and container. if ($this->booted) { - drupal_container(NULL, TRUE); $this->booted = FALSE; $this->boot(); } @@ -255,12 +252,11 @@ protected function initializeContainer() { $this->moduleList = $this->newModuleList; unset($this->newModuleList); } - // Second, verify that some other request -- for example on another - // web frontend or during the installer -- changed the list of enabled - // modules. + // Second, verify that some other request, e.g., on another web frontend, + // changed the list of enabled modules. if (isset($this->container)) { $module_list = $this->moduleList ?: $this->container->get('config.factory')->get('system.module')->load()->get('enabled'); - if (array_keys((array)$module_list) !== $this->container->getParameter('container.modules')) { + if (array_keys((array) $module_list) !== $this->container->getParameter('container.modules')) { unset($this->container); } } @@ -294,10 +290,14 @@ protected function buildContainer() { $container->setParameter('container.bundles', $this->bundleClasses); $container->setParameter('container.modules', array_keys($this->moduleList)); - // Merge in the minimal bootstrap container. - if ($bootstrap_container = drupal_container()) { - $container->merge($bootstrap_container); + // Merge in the minimal bootstrap container, unless it contains the kernel + // already. + // @todo Stop this merge mess. Either merge $this->baseContainer or nothing at all. + if (!isset($this->drupalContainer)) { + $this->drupalContainer = clone drupal_container(NULL, TRUE); } + $container->merge($this->drupalContainer); + foreach ($this->bundles as $bundle) { $bundle->build($container); } diff --git a/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php index f4dd294..ae31e6c 100644 --- a/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php @@ -35,26 +35,31 @@ function testCompileDIC() { // We need to be able to restore it to the correct one at the end of this // test. $original_container = drupal_container(); - $classloader = drupal_classloader(); - $configuration = array( + + $bootstrap_container = drupal_bootstrap_container(); + $php_storage_configuration = array( 'bin' => 'service_container', - 'directory' => DRUPAL_ROOT . '/' . variable_get('file_public_path', conf_path() . '/files') . '/php', + 'directory' => $this->public_files_directory . '/php', 'secret' => $GLOBALS['drupal_hash_salt'], ); - // @todo: write a memory based storage backend for testing. - $php_storage = new MTimeProtectedFastFileStorage($configuration); + // @todo Write a memory based storage backend for testing. + $bootstrap_container + ->register('php_storage.service_container', 'Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage') + ->addArgument($php_storage_configuration); + + $kernel = new DrupalKernel('testing', TRUE, $bootstrap_container); $module_enabled = array( 'system' => 'system', - 'user' => 'user', ); - $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); $kernel->updateModules($module_enabled); $kernel->boot(); + // Instantiate it a second time and we should get the compiled Container // class. - $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + $kernel = new DrupalKernel('testing', TRUE, $bootstrap_container); $kernel->updateModules($module_enabled); $kernel->boot(); + $container = $kernel->getContainer(); $refClass = new ReflectionClass($container); $is_compiled_container = @@ -62,15 +67,17 @@ function testCompileDIC() { !$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder'); $this->assertTrue($is_compiled_container); - // Reset the container. - drupal_container(NULL, TRUE); - - // Now use the read-only storage implementation, simulating a "production" + // Now use the read-only storage implementation, simulating a production // environment. - $php_storage = new FileReadOnlyStorage($configuration); - $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + $readonly_bootstrap_container = clone $bootstrap_container; + $readonly_bootstrap_container + ->register('php_storage.service_container', 'Drupal\Component\PhpStorage\FileReadOnlyStorage') + ->addArgument($php_storage_configuration); + + $kernel = new DrupalKernel('testing', TRUE, $readonly_bootstrap_container); $kernel->updateModules($module_enabled); $kernel->boot(); + $container = $kernel->getContainer(); $refClass = new ReflectionClass($container); $is_compiled_container = @@ -84,24 +91,25 @@ function testCompileDIC() { // modules. $this->assertFalse($container->has('bundle_test_class')); - // Reset the container. - drupal_container(NULL, TRUE); - // Add another module so that we can test that the new module's bundle is // registered to the new container. $module_enabled['bundle_test'] = 'bundle_test'; - $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + + $kernel = new DrupalKernel('testing', TRUE, $readonly_bootstrap_container); $kernel->updateModules($module_enabled); $kernel->boot(); + // Instantiate it a second time and we should still get a ContainerBuilder // class because we are using the read-only PHP storage. - $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + $kernel = new DrupalKernel('testing', TRUE, $readonly_bootstrap_container); $kernel->updateModules($module_enabled); $kernel->boot(); + $container = $kernel->getContainer(); $refClass = new ReflectionClass($container); $is_container_builder = $refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder'); $this->assertTrue($is_container_builder); + // Assert that the new module's bundle was registered to the new container. $this->assertTrue($container->has('bundle_test_class')); diff --git a/index.php b/index.php index 4d56290..563bd7f 100644 --- a/index.php +++ b/index.php @@ -28,7 +28,7 @@ drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); // @todo Figure out how best to handle the Kernel constructor parameters. -$kernel = new DrupalKernel('prod', FALSE, drupal_classloader(), drupal_php_storage('service_container')); +$kernel = new DrupalKernel('prod', FALSE, drupal_bootstrap_container()); // Create a request object from the HTTPFoundation. $request = Request::createFromGlobals();