diff --git a/core/includes/common.inc b/core/includes/common.inc index bd263ec..10c8cf5 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -4813,8 +4813,6 @@ function _drupal_bootstrap_full($skip = FALSE) { if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') { // Prior to invoking hook_init(), initialize the theme (potentially a custom // one for this page), so that: - // - Modules with hook_init() implementations that call theme() or - // theme_get_registry() don't initialize the incorrect theme. // - The theme can have hook_*_alter() implementations affect page building // (e.g., hook_form_alter(), hook_node_view_alter(), hook_page_alter()), // ahead of when rendering starts. diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 7f4b26b..8f03cee 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -346,6 +346,11 @@ function install_begin_request(&$install_state) { // (as opposed to the cache backend) so we can afford having a null // implementation here. $container->register('lock', 'Drupal\Core\Lock\NullLockBackend'); + + // The theme registry will use the Cache\MemoryBackend, as defined below. + $container + ->register('theme.registry', 'Drupal\Core\Theme\Registry'); + drupal_container($container); } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index e16c8d2..99b50ee 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -288,18 +288,7 @@ function _drupal_theme_initialize($theme, $base_theme = array()) { * Drupal\Core\Utility\ThemeRegistry class. */ function theme_get_registry($complete = TRUE) { - // Use the advanced drupal_static() pattern, since this is called very often. - static $drupal_static_fast; - if (!isset($drupal_static_fast)) { - $drupal_static_fast['registry'] = &drupal_static('theme_get_registry'); - } - $registry = &$drupal_static_fast['registry']; - - // @todo DIC this. - if (!isset($registry)) { - $registry = new Registry($GLOBALS['theme_info'], $GLOBALS['base_theme_info'], $GLOBALS['theme_engine']); - } - return $registry->get($complete); + return drupal_container()->get('theme.registry')->get($complete); } /** @@ -308,11 +297,10 @@ function theme_get_registry($complete = TRUE) { * This function should be called when modules are added to the system, or when * a dynamic system needs to add more theme hooks. * - * @todo Remove this. + * @todo Remove this. "Rebuild" is a misnomer in the first place. */ function drupal_theme_rebuild() { - drupal_static_reset('theme_get_registry'); - cache()->invalidateTags(array('theme_registry' => TRUE)); + drupal_container()->get('theme.registry')->reset(); } /** diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index 7baa164..9ccd5c6 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -77,7 +77,10 @@ function _drupal_maintenance_theme() { $base_theme[] = $new_base_theme = $themes[$themes[$ancestor]->base_theme]; $ancestor = $themes[$ancestor]->base_theme; } - _drupal_theme_initialize($themes[$theme], array_reverse($base_theme), '_theme_load_offline_registry'); + _drupal_theme_initialize($themes[$theme], array_reverse($base_theme)); + // Prime the theme registry. + // @todo Remove global theme variables. + drupal_container()->get('theme.registry'); // These are usually added from system_init() -except maintenance.css. // When the database is inactive it's not called so we add it here. @@ -89,15 +92,6 @@ function _drupal_maintenance_theme() { } /** - * Builds the registry when the site needs to bypass any database calls. - * - * @todo Remove this. - */ -function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) { - return theme_get_registry(); -} - -/** * Returns HTML for a list of maintenance tasks to perform. * * @param $variables diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index 52af901..ead6d7c 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -119,6 +119,17 @@ public function build(ContainerBuilder $container) { ->addArgument(new Reference('database')) ->addArgument(new Reference('lock')); + $container + ->register('cache.theme', 'Drupal\Core\Cache\CacheBackendInterface') + ->setFactoryClass('Drupal\Core\Cache\CacheFactory') + ->setFactoryMethod('get') + // @todo Cache bins/services should not map 1:1 to tables. 'theme' fails + // with error {cache_theme} table does not exist. + ->addArgument('cache'); + $container + ->register('theme.registry', 'Drupal\Core\Theme\Registry') + ->addArgument(new Reference('cache.theme')); + $this->registerTwig($container); // Add the entity query factory. diff --git a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php index 242f935..0d9f76d 100644 --- a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php @@ -29,8 +29,6 @@ public function onKernelRequestLegacy(GetResponseEvent $event) { if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { // Prior to invoking hook_init(), initialize the theme (potentially a // custom one for this page), so that: - // - Modules with hook_init() implementations that call theme() or - // theme_get_registry() don't initialize the incorrect theme. // - The theme can have hook_*_alter() implementations affect page // building (e.g., hook_form_alter(), hook_node_view_alter(), // hook_page_alter()), ahead of when rendering starts. diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index ac2232f..97c5f09 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -88,30 +88,62 @@ class Registry { */ protected $runtimeRegistry; + protected $cache; + /** * Constructs a new theme registry instance. * - * @param object $theme + * @todo Inject new ModuleHandler. + */ + public function __construct(CacheBackendInterface $cache) { + $this->cache = $cache; + $this->init(); + } + + /** + * DIE. + * + * @global object $theme_info * An object with (at least) the following information: * - uri: The path to the theme. * - owner: The name of the theme's base theme. * - engine: The name of the theme engine to use. - * @param array $base_themes + * @global array $base_theme_info * (optional) An array of objects that represent the base themes of $theme, * each having the same properties as $theme above, ordered by base theme * hierarchy; i.e., the first element is the root of all themes. - * @param string $theme_engine + * @global string $theme_engine * The name of the theme engine. * - * @todo Remove $theme_engine, duplicates ->engine. - * @todo Stack all themes into a single $themes in appropriate order. + * @todo Remove global $theme_engine, it duplicates ->engine. + * @todo Inject ThemeHandler, so as to remove all of these globals, + * in this way: + * - theme engines are dependencies of themes. + * - theme engines are actually treated *identically* to themes. (also: + * remove the /engines subdirectory) + * - base themes are dependencies of themes. + * As a result: + * - $theme->requires == should contain the full stack of dependencies, + * in the correct order. */ - public function __construct($theme, array $base_themes = array(), $theme_engine) { - // @todo Inject Cache. - // @todo Inject new ModuleHandler. - $this->theme = $theme; - $this->base_themes = $base_themes; - $this->engine = $theme_engine; + public function init() { + // #1: The theme registry might get instantiated before the theme was + // initialized. Cope with that. + if (!isset($GLOBALS['theme_info'])) { + unset($this->runtimeRegistry); + unset($this->registry); + drupal_theme_initialize(); + } + // #2: The testing framework only cares for the global $theme variable at + // this point. Cope with that. + if ($GLOBALS['theme'] != $GLOBALS['theme_info']->name) { + unset($this->runtimeRegistry); + unset($this->registry); + drupal_theme_initialize(); + } + $this->theme = $GLOBALS['theme_info']; + $this->base_themes = $GLOBALS['base_theme_info']; + $this->engine = $GLOBALS['theme_engine']; } /** @@ -177,9 +209,8 @@ public function load($complete = TRUE) { return $this->getRuntime(); } // Check the theme registry cache; if it exists, use it. - $cached = cache()->get('theme_registry:' . $this->theme->name); - if (isset($cached->data)) { - $registry = $cached->data; + if ($cache = $this->cache->get('theme_registry:' . $this->theme->name)) { + $registry = $cache->data; } else { // If not, build one and cache it. @@ -200,7 +231,7 @@ public function load($complete = TRUE) { * The complete theme registry. */ public function save($registry) { - cache()->set('theme_registry:' . $this->theme->name, $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); + $this->cache->set('theme_registry:' . $this->theme->name, $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); } /** @@ -235,7 +266,7 @@ public function build() { $registry = array(); // hook_theme() implementations of modules are always the same. - if ($cached = cache()->get('theme_registry:build:modules')) { + if ($cached = $this->cache->get('theme_registry:build:modules')) { $registry = $cached->data; } else { @@ -245,7 +276,7 @@ public function build() { // Only cache this registry if all modules are loaded. // @todo Get rid of these checks. if (module_load_all(NULL)) { - cache()->set("theme_registry:build:modules", $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); + $this->cache->set("theme_registry:build:modules", $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); } } @@ -318,6 +349,10 @@ public function build() { */ public function processExtension(&$registry, $type, $name, $theme_name, $theme_path) { $function = $name . '_theme'; + // Extensions do not necessarily have to implement hook_theme(). + if (!function_exists($function)) { + return; + } foreach ($function($registry, $type, $theme_name, $theme_path) as $hook => $info) { // Ensure this hook key exists; it will be set either way. $registry += array($hook => array( @@ -461,7 +496,7 @@ public function rebuild() { public function reset() { unset($this->runtimeRegistry); unset($this->registry); - cache()->invalidateTags(array('theme_registry' => TRUE)); + $this->cache->invalidateTags(array('theme_registry' => TRUE)); } /** diff --git a/core/lib/Drupal/Core/Utility/ThemeRegistry.php b/core/lib/Drupal/Core/Utility/ThemeRegistry.php index bc9691c..ce4de7f 100644 --- a/core/lib/Drupal/Core/Utility/ThemeRegistry.php +++ b/core/lib/Drupal/Core/Utility/ThemeRegistry.php @@ -74,6 +74,7 @@ function __construct($cid, $bin, $tags) { * initialized to NULL. */ function initializeRegistry() { + // @todo DIC this. $this->completeRegistry = theme_get_registry(); return array_fill_keys(array_keys($this->completeRegistry), NULL); @@ -109,6 +110,7 @@ public function offsetGet($offset) { * Implements CacheArray::resolveCacheMiss(). */ public function resolveCacheMiss($offset) { + // @todo DIC this. if (!isset($this->completeRegistry)) { $this->completeRegistry = theme_get_registry(); } diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php index 0001cba..c5a64f9 100644 --- a/core/modules/system/theme.api.php +++ b/core/modules/system/theme.api.php @@ -118,7 +118,7 @@ function hook_preprocess(&$variables, $hook) { } if (!isset($hooks)) { - $hooks = theme_get_registry(); + $hooks = theme_get_registry(FALSE); } // Determine the primary theme function argument.