diff -u b/core/includes/common.inc b/core/includes/common.inc --- b/core/includes/common.inc +++ b/core/includes/common.inc @@ -5160,6 +5160,9 @@ * - 'name': Name of file without the extension. */ function drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1) { + // As SystemListing is required to build a dependency injection container + // from scratch and SystemListingInfo only extends SystemLising, this + // functionality needs to be hardwired. $listing = new SystemListingInfo(); return $listing->scan($mask, $directory, $key, $min_depth); } diff -u b/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php --- b/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -35,14 +35,17 @@ * * @var array */ - protected $moduleList; + protected $moduleList = array(); /** - * An array of module data as returned by system_rebuild_module_data(). + * An array of module data objects. + * + * The data objects have the same datastructure as returned by + * file_scan_directory() but only the uri property is used. * * @var array */ - protected $moduleData; + protected $moduleData = array(); /** * PHP code storage object to use for the compiled container. @@ -77,19 +80,19 @@ * Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use * this value currently. Pass TRUE. * @param \Symfony\Component\ClassLoader\UniversalClassLoader $class_loader - * (optional) A classloader object. Required when $storage is set and - * also when $module_list is not set. + * A classloader object. 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 PHP load and save. - * @param array $module_list - * (optional) The array of enabled modules as returned by module_list(). + * (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. */ - public function __construct($environment, $debug, UniversalClassLoader $class_loader = NULL, PhpStorageInterface $storage = NULL, array $module_list = NULL) { + public function __construct($environment, $debug, UniversalClassLoader $class_loader, PhpStorageInterface $storage = NULL) { parent::__construct($environment, $debug); $this->storage = $storage; - $this->moduleList = $module_list ?: array(); $this->classLoader = $class_loader; - $this->moduleList = $module_list; } /** @@ -129,9 +132,40 @@ $module_list = $module_list['enabled']; $this->moduleList = $module_list; } + + $namespaces = $this->classLoader->getNamespaces(); + foreach ($this->moduleList as $module => $weight) { + // When installing new modules, the module list passed to + // updateModules() does not yet have their namespace registered. + $namespace = 'Drupal\\' . $module; + if (!isset($namespaces[$namespace]) && $this->moduleData($module)) { + $this->classLoader->registerNamespace($namespace, dirname(DRUPAL_ROOT . '/' . $this->moduleData($module)->uri) . '/lib'); + } + $camelized = ContainerBuilder::camelize($module); + $class = "Drupal\\{$module}\\{$camelized}Bundle"; + if (class_exists($class)) { + $bundles[] = new $class(); + $this->bundleClasses[] = $class; + } + } + return $bundles; + } + + /** + * Returns module data on the filesystem. + * + * @param $module + * The name of the module. + * @return \stdClass|bool + * Returns a stdClass object if the module data is found containing at + * least an uri property containing the module path for example + * core/modules/user/user.module. + */ + protected function moduleData($module) { if (!$this->moduleData) { - // Find filenames and prime the classloader. First, we need to add - // profiles because modules migh tbe inside those. + // Find filenames to prime the classloader. First, find profiles. + // Profiles might want to add a bundle too and they also can contain + // modules. $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)); @@ -142,24 +176,11 @@ // actual profile always has precedence. array_unshift($profiles, $parent_profile_config['parent_profile']); } + // Now find modules. $modules_scanner = new SystemListing($profiles); $this->moduleData = $all_profiles + $modules_scanner ->scan('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules'); } - - $namespaces = $this->classLoader->getNamespaces(); - foreach ($this->moduleList as $module => $weight) { - $namespace = 'Drupal\\' . $module; - if (!isset($namespaces[$namespace]) && isset($this->moduleData[$module])) { - $this->classLoader->registerNamespace($namespace, dirname(DRUPAL_ROOT . '/' . $this->moduleData[$module]->uri) . '/lib'); - } - $camelized = ContainerBuilder::camelize($module); - $class = "Drupal\\{$module}\\{$camelized}Bundle"; - if (class_exists($class)) { - $bundles[] = new $class(); - $this->bundleClasses[] = $class; - } - } - return $bundles; + return isset($this->moduleData[$module]) ? $this->moduleData[$module] : FALSE; } /** @@ -188,6 +209,7 @@ */ protected function getClassName() { $parts = array('service_container', $this->environment, $this->debug); + // Make sure to use a testing-specific container even in the parent site. if (!empty($GLOBALS['drupal_test_info']['test_run_id'])) { $parts[] = $GLOBALS['drupal_test_info']['test_run_id']; } @@ -310,2 +332,3 @@ } + } diff -u b/core/lib/Drupal/Core/SystemListing.php b/core/lib/Drupal/Core/SystemListing.php --- b/core/lib/Drupal/Core/SystemListing.php +++ b/core/lib/Drupal/Core/SystemListing.php @@ -1,7 +1,19 @@ 'system', 'user' => 'user', ); - $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage, $module_enabled); + $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, $module_enabled); + $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + $kernel->updateModules($module_enabled); $kernel->boot(); $container = $kernel->getContainer(); $refClass = new ReflectionClass($container); @@ -66,7 +68,8 @@ // Now use the read-only storage implementation, simulating a "production" // environment. $php_storage = new FileReadOnlyStorage($configuration); - $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage, $module_enabled); + $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + $kernel->updateModules($module_enabled); $kernel->boot(); $container = $kernel->getContainer(); $refClass = new ReflectionClass($container); @@ -87,11 +90,13 @@ // 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, $module_enabled); + $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + $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, $module_enabled); + $kernel = new DrupalKernel('testing', FALSE, $classloader, $php_storage); + $kernel->updateModules($module_enabled); $kernel->boot(); $container = $kernel->getContainer(); $refClass = new ReflectionClass($container);