diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 11991bb..740a0d4 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -894,7 +894,7 @@ function drupal_get_filename($type, $name, $filename = NULL) { // Verify that we have an keyvalue service before using it. This is required // because this function is called during installation. // @todo Inject database connection into KeyValueStore\DatabaseStorage. - if (drupal_container()->hasDefinition('keyvalue') && function_exists('db_query')) { + if (drupal_container()->has('keyvalue') && function_exists('db_query')) { try { $file_list = state()->get('system.' . $type . '.files'); if ($file_list && isset($file_list[$name]) && file_exists(DRUPAL_ROOT . '/' . $file_list[$name])) { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index b1d3b50..cc6c6ac 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1474,9 +1474,10 @@ function install_bootstrap_full(&$install_state) { module_list_reset(); // @todo The constructor parameters for the Kernel class are for environment, // e.g. 'prod', 'dev', and a boolean indicating whether it is in debug mode. - // Drupal does not currently make use of either of these, though that may - // change with http://drupal.org/node/1537198. - $kernel = new DrupalKernel('prod', FALSE); + // Drupal does not currently make use of the environment parameter, but + // debug mode can be used to prevent the DI container from being dumped to + // PHP, which is what we want during installation. + $kernel = new DrupalKernel('prod', TRUE); $kernel->boot(); drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); } diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index ed7171a..4c971c3 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -8,6 +8,7 @@ namespace Drupal\Core; use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -61,13 +62,29 @@ public function build(ContainerBuilder $container) { ->addArgument(new Reference('database')) ->addArgument(new Reference('lock')); - $container->register('router.dumper', '\Drupal\Core\Routing\MatcherDumper') + $container->register('router.dumper', 'Drupal\Core\Routing\MatcherDumper') ->addArgument(new Reference('database')); $container->register('router.builder', 'Drupal\Core\Routing\RouteBuilder') ->addArgument(new Reference('router.dumper')); - $container->register('matcher', 'Drupal\Core\LegacyUrlMatcher'); - $container->register('router_listener', 'Drupal\Core\EventSubscriber\RouterListener') + $container->register('matcher', 'Drupal\Core\Routing\ChainMatcher'); + $container->register('legacy_url_matcher', 'Drupal\Core\LegacyUrlMatcher') + ->addTag('chained_matcher'); + + $container->register('nested_matcher', 'Drupal\Core\Routing\NestedMatcher') + ->addTag('chained_matcher', array('priority' => 5)); + + $container->register('path_matcher', 'Drupal\Core\Routing\PathMatcher') + ->addArgument(new Reference('database')) + ->addTag('nested_matcher', array('method' => 'setInitialMatcher')); + $container->register('http_method_matcher', 'Drupal\Core\Routing\HttpMethodMatcher') + ->addTag('nested_matcher', array('method' => 'addPartialMatcher')); + $container->register('first_entry_final_matcher', 'Drupal\Core\Routing\FirstEntryFinalMatcher') + ->addTag('nested_matcher', array('method' => 'setFinalMatcher')); + + $container->register('router_processor_subscriber', 'Drupal\Core\EventSubscriber\RouteProcessorSubscriber') + ->addTag('kernel.event_subscriber'); + $container->register('router_listener', 'Symfony\Component\HttpKernel\EventListener\RouterListener') ->addArgument(new Reference('matcher')) ->addTag('kernel.event_subscriber'); $container->register('content_negotiation', 'Drupal\Core\ContentNegotiation'); @@ -98,6 +115,7 @@ public function build(ContainerBuilder $container) { ->setFactoryClass('Drupal\Core\ExceptionController') ->setFactoryMethod('getExceptionListener'); + $container->addCompilerPass(new RegisterMatchersPass(), PassConfig::TYPE_AFTER_REMOVING); // Add a compiler pass for registering event subscribers. $container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING); } diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterMatchersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterMatchersPass.php new file mode 100644 index 0000000..b7a3246 --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterMatchersPass.php @@ -0,0 +1,37 @@ +hasDefinition('matcher')) { + return; + } + $matcher = $container->getDefinition('matcher'); + $has_nested_matcher = FALSE; + foreach ($container->findTaggedServiceIds('chained_matcher') as $id => $attributes) { + if ($id == 'nested_matcher') { + $has_nested_matcher = TRUE; + } + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $matcher->addMethodCall('add', array(new Reference($id), $priority)); + } + if ($has_nested_matcher) { + $nested = $container->getDefinition('nested_matcher'); + foreach ($container->findTaggedServiceIds('nested_matcher') as $id => $attributes) { + $method = $attributes[0]['method']; + $nested->addMethodCall($method, array(new Reference($id))); + } + } + } +} diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 497aa8d..42e66a7 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -76,35 +76,41 @@ public function registerBundles() { * Initializes the service container. */ protected function initializeContainer() { - // While the default Symfony class name only depends on the environment, for - // testing purposes we can't use that because there would be a collision as - // each test method creates a new kernel. On the other hand, the container - // only depends on the enabled modules (and only on those that provide - // bundles) so we base the name of the container class on the hash of the - // enabled modules. We can't directly use the hash though because PHP - // identifiers always start with a letter and hashes don't so we add a - // character to the beginning. This mechanism also avoids the problem of - // needing to rebuild the DIC at the right time on module enable: simply on - // the next request the hash will change and so the container will be - // rebuilt. - $class = 'c' . $this->systemList['module_enabled_hash']; - $cache_file = $class . '.php'; - - $storage = drupal_php_storage('service_container'); - // First, try to load. - if (!class_exists($class)) { - $storage->load($cache_file); - } - // If the load succeeded or the class already existed, use it. - if (class_exists($class)) { - $this->container = new $class; + if ($this->debug) { + $this->container = $this->buildContainer(); } else { - $this->container = $this->buildContainer(); - if (!$this->dumpDrupalContainer($cache_file, $this->container, $class, $this->getContainerBaseClass(), $storage)) { - $exception = 'Container cannot be written to disk'; + // While the default Symfony class name only depends on the environment, for + // testing purposes we can't use that because there would be a collision as + // each test method creates a new kernel. On the other hand, the container + // only depends on the enabled modules (and only on those that provide + // bundles) so we base the name of the container class on the hash of the + // enabled modules. We can't directly use the hash though because PHP + // identifiers always start with a letter and hashes don't so we add a + // character to the beginning. This mechanism also avoids the problem of + // needing to rebuild the DIC at the right time on module enable: simply on + // the next request the hash will change and so the container will be + // rebuilt. + $class = 'c' . $this->systemList['module_enabled_hash']; + $cache_file = $class . '.php'; + + $storage = drupal_php_storage('service_container'); + // First, try to load. + if (!class_exists($class)) { + $storage->load($cache_file); + } + // If the load succeeded or the class already existed, use it. + if (class_exists($class)) { + $this->container = new $class; + } + else { + $this->container = $this->buildContainer(); + if (!$this->dumpDrupalContainer($cache_file, $this->container, $class, $this->getContainerBaseClass(), $storage)) { + $exception = 'Container cannot be written to disk'; + } } } + $this->container->set('kernel', $this); drupal_container($this->container); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index da68586..24bf1f2 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -718,12 +718,11 @@ protected function setUp() { $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules)))); } - // Now that all required modules are enabled, reset drupal_container() and - // create a new DrupalKernel for testing purposes, which when booted, will - // store a new dependency injection container in drupal_container(). - // Drupal\simpletest\TestBase::tearDown() restores the original container. + // Create a new DrupalKernel for testing purposes, now that all required + // modules have been enabled. This also stores a new dependency injection + // container in drupal_container(). Drupal\simpletest\TestBase::tearDown() + // restores the original container. // @see Drupal\Core\DrupalKernel::initializeContainer() - drupal_container(NULL, TRUE); $this->kernel = new DrupalKernel('testing', FALSE); // Booting the kernel is necessary to initialize the new DIC. While // normally the kernel gets booted on demand in