From f3d2b417eb839fd6586965e0623ee799d129adf8 Mon Sep 17 00:00:00 2001 From: Mark Carver Date: Sat, 29 Jun 2013 22:05:27 -0500 Subject: Mark Carver: Generated with Drush iq --- core/lib/Drupal/Core/DrupalKernel.php | 167 +++++++++++++++++++++---- core/lib/Drupal/Core/DrupalKernelInterface.php | 13 ++ 2 files changed, 159 insertions(+), 21 deletions(-) diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index af1fe52..08cf959 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -29,8 +29,8 @@ * 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 + * needed by core, e.g. for processing tagged services. Each module or theme 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. */ @@ -88,6 +88,34 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { protected $moduleData = array(); /** + * Holds the list of enabled themes. + * + * @var array + * An associative array whose keys are theme names and whose values are + * ignored. + */ + protected $themeList; + + /** + * Holds an updated list of enabled themes. + * + * @var array + * An associative array whose keys are theme names and whose values are + * ignored. + */ + protected $newThemeList; + + /** + * An array of theme data objects. + * + * The data objects have the same data structure as returned by + * file_scan_directory() but only the uri property is used. + * + * @var array + */ + protected $themeData = array(); + + /** * PHP code storage object to use for the compiled container. * * @var \Drupal\Component\PhpStorage\PhpStorageInterface @@ -102,7 +130,8 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { protected $classLoader; /** - * Config storage object used for reading enabled modules configuration. + * Config storage object used for reading enabled module and theme + * configuration. * * @var \Drupal\Core\Config\StorageInterface */ @@ -233,7 +262,7 @@ public function discoverServiceProviders() { $this->moduleList = isset($module_list['enabled']) ? $module_list['enabled'] : array(); } $module_filenames = $this->getModuleFileNames(); - $this->registerNamespaces($this->getModuleNamespaces($module_filenames)); + $this->registerNamespaces($this->getNamespaces($module_filenames)); // Load each module's serviceProvider class. foreach ($this->moduleList as $module => $weight) { @@ -250,6 +279,32 @@ public function discoverServiceProviders() { } } + // Ensure we know what themes are enabled and that their namespaces are + // registered. + if (!isset($this->themeList)) { + $theme_list = $this->configStorage->read('system.theme'); + $this->themeList = isset($theme_list['enabled']) ? $theme_list['enabled'] : array(); + } + $theme_filenames = $this->getThemeFileNames(); + $this->registerNamespaces($this->getNamespaces($theme_filenames)); + + // Load each theme's serviceProvider class. + foreach ($this->themeList as $theme => $weight) { + $camelized = ContainerBuilder::camelize($theme); + $name = "{$camelized}ServiceProvider"; + $class = "Drupal\\{$theme}\\{$name}"; + if (class_exists($class)) { + $serviceProviders[$name] = new $class(); + $this->serviceProviderClasses[] = $class; + } + if (!empty($theme_filenames[$theme])) { + $filename = dirname($theme_filenames[$theme]) . "/$theme.services.yml"; + if (file_exists($filename)) { + $this->serviceYamls[] = $filename; + } + } + } + // Add site specific or test service providers. if (!empty($GLOBALS['conf']['container_service_providers'])) { foreach ($GLOBALS['conf']['container_service_providers'] as $name => $class) { @@ -261,6 +316,7 @@ public function discoverServiceProviders() { if (!empty($GLOBALS['conf']['container_yamls'])) { $this->serviceYamls = array_merge($this->serviceYamls, $GLOBALS['conf']['container_yamls']); } + return $serviceProviders; } @@ -328,6 +384,25 @@ protected function moduleData($module) { } /** + * Returns theme data on the filesystem. + * + * @param $theme + * The name of the theme. + * + * @return \stdClass|bool + * Returns a stdClass object if the theme data is found containing at + * least an uri property with the theme path, for example + * core/themes/user/user.theme. + */ + protected function themeData($theme) { + if (!$this->themeData) { + $scanner = new SystemListing(); + $this->themeData = $scanner->scan('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.theme$/', 'themes'); + } + return isset($this->themeData[$theme]) ? $this->themeData[$theme] : FALSE; + } + + /** * Implements Drupal\Core\DrupalKernelInterface::updateModules(). * * @todo Remove obsolete $module_list parameter. Only $module_filenames is @@ -348,6 +423,26 @@ public function updateModules(array $module_list, array $module_filenames = arra } /** + * Implements Drupal\Core\DrupalKernelInterface::updateThemes(). + * + * @todo Remove obsolete $theme_list parameter. Only $theme_filenames is + * needed. + */ + public function updateThemes(array $theme_list, array $theme_filenames = array()) { + $this->newThemeList = $theme_list; + foreach ($theme_filenames as $theme => $filename) { + $this->themeData[$theme] = (object) array('uri' => $filename); + } + // If we haven't yet booted, we don't need to do anything: the new theme + // list will take effect when boot() is called. If we have already booted, + // then reboot in order to refresh the serviceProvider list and container. + if ($this->booted) { + $this->booted = FALSE; + $this->boot(); + } + } + + /** * Returns the classname based on environment and testing prefix. * * @return string @@ -403,7 +498,8 @@ protected function initializeContainer() { $this->persistServices($persist); } } - // First check whether the list of modules changed in this request. + // First check whether the list of modules or themes changed in this + // request. if (isset($this->newModuleList)) { if (isset($this->container) && isset($this->moduleList) && array_keys($this->moduleList) !== array_keys($this->newModuleList)) { unset($this->container); @@ -411,20 +507,34 @@ protected function initializeContainer() { $this->moduleList = $this->newModuleList; unset($this->newModuleList); } + if (isset($this->newThemeList)) { + if (isset($this->container) && isset($this->themeList) && array_keys($this->themeList) !== array_keys($this->newthemeList)) { + unset($this->container); + } + $this->themeList = $this->newThemeList; + unset($this->newThemeList); + } // Second, check if some other request -- for example on another web - // frontend or during the installer -- changed the list of enabled modules. + // frontend or during the installer -- changed the list of enabled modules + // or themes. if (isset($this->container)) { // All namespaces must be registered before we attempt to use any service // from the container. - $container_modules = $this->container->getParameter('container.modules'); $namespaces_before = $this->classLoader->getPrefixes(); - $this->registerNamespaces($this->getModuleNamespaces($container_modules)); + $container_modules = $this->container->getParameter('container.modules'); + $this->registerNamespaces($this->getNamespaces($container_modules)); + $container_themes = $this->container->getParameter('container.themes'); + $this->registerNamespaces($this->getNamespaces($container_themes)); - // If 'container.modules' is wrong, the container must be rebuilt. + // If 'container.modules' or 'container.themes' is wrong, the container + // must be rebuilt. if (!isset($this->moduleList)) { $this->moduleList = $this->container->get('config.factory')->get('system.module')->load()->get('enabled'); } - if (array_keys($this->moduleList) !== array_keys($container_modules)) { + if (!isset($this->themeList)) { + $this->themeList = $this->container->get('config.factory')->get('system.theme')->load()->get('enabled'); + } + if (array_keys($this->moduleList) !== array_keys($container_modules) || array_keys($this->themeList) !== array_keys($container_themes)) { $persist = $this->getServicesToPersist(); unset($this->container); // Revert the class loader to its prior state. However, @@ -443,7 +553,7 @@ protected function initializeContainer() { // The namespaces are marked as persistent, so objects like the annotated // class discovery still has the right object. We may have updated the - // list of modules, so set it. + // list of modules or themes, so set it. if ($this->container->initialized('container.namespaces')) { $this->container->get('container.namespaces')->exchangeArray($this->container->getParameter('container.namespaces')); } @@ -505,16 +615,18 @@ protected function buildContainer() { $container->set('kernel', $this); $container->setParameter('container.service_providers', $this->serviceProviderClasses); $container->setParameter('container.modules', $this->getModuleFileNames()); + $container->setParameter('container.themes', $this->getThemeFileNames()); // Get a list of namespaces and put it onto the container. - $namespaces = $this->getModuleNamespaces($this->getModuleFileNames()); + $namespaces = $this->getNamespaces(array_merge_recursive($this->getModuleFileNames(), $this->getThemeFileNames())); + // Add all components in \Drupal\Core and \Drupal\Component that have a // Plugin directory. foreach (array('Core', 'Component') as $parent_directory) { $path = DRUPAL_ROOT . '/core/lib/Drupal/' . $parent_directory; foreach (new \DirectoryIterator($path) as $component) { if (!$component->isDot() && is_dir($component->getPathname() . '/Plugin')) { - $namespaces['Drupal\\' . $parent_directory .'\\' . $component->getFilename()] = DRUPAL_ROOT . '/core/lib'; + $namespaces['Drupal\\' . $parent_directory . '\\' . $component->getFilename()] = DRUPAL_ROOT . '/core/lib'; } } } @@ -615,8 +727,8 @@ protected function getHttpKernel() { * implementing LoaderInterface as its only parameter. This is part of the * Config compoment from Symfony, which is not provided by Drupal core. * - * Modules wishing to provide an extension to this class which uses this - * method are responsible for ensuring the Config component exists. + * Modules or themes wishing to provide an extension to this class which uses + * this method are responsible for ensuring the Config component exists. */ public function registerContainerConfiguration(LoaderInterface $loader) { } @@ -634,6 +746,17 @@ protected function storage() { } /** + * Gets the namespaces of each enabled module or theme. + */ + protected function getNamespaces($fileNames) { + $namespaces = array(); + foreach ($fileNames as $name => $filename) { + $namespaces["Drupal\\$name"] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib'; + } + return $namespaces; + } + + /** * Returns the file name for each enabled module. */ protected function getModuleFileNames() { @@ -647,14 +770,16 @@ protected function getModuleFileNames() { } /** - * Gets the namespaces of each enabled module. + * Returns the file name for each enabled theme. */ - protected function getModuleNamespaces($moduleFileNames) { - $namespaces = array(); - foreach ($moduleFileNames as $module => $filename) { - $namespaces["Drupal\\$module"] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib'; + protected function getThemeFileNames() { + $filenames = array(); + foreach ($this->themeList as $theme => $weight) { + if ($data = $this->themeData($theme)) { + $filenames[$theme] = $data->uri; + } } - return $namespaces; + return $filenames; } /** diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php index 96b2f92..dd3da7d 100644 --- a/core/lib/Drupal/Core/DrupalKernelInterface.php +++ b/core/lib/Drupal/Core/DrupalKernelInterface.php @@ -62,4 +62,17 @@ public function getContainer(); * List of module filenames, keyed by module name. */ public function updateModules(array $module_list, array $module_filenames = array()); + + /** + * Updates the kernel's list of themes to the new list. + * + * The kernel needs to update its bundle list and container to match the new + * list. + * + * @param array $theme_list + * The new list of themes. + * @param array $theme_filenames + * List of theme filenames, keyed by theme name. + */ + public function updateThemes(array $theme_list, array $theme_filenames = array()); } -- 1.8.2