From 08ce5a7001677e9ffb86c6b22f13893a0985f872 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Sun, 15 Mar 2015 20:23:37 +0000 Subject: [PATCH] Issue #2448847 by dawehner, arlinsandbulte: [regression] Themes unable to implement hook_theme_registry_alter() --- core/core.services.yml | 6 +++- core/lib/Drupal/Core/Theme/Registry.php | 23 +++++++++++++-- core/lib/Drupal/Core/Theme/ThemeManager.php | 29 +++++++++++++++---- .../Core/Theme/ThemeManagerInterface.php | 22 ++++++++++++++ .../system/src/Tests/Theme/RegistryTest.php | 21 +++++++++++++- .../tests/themes/test_theme/test_theme.theme | 7 +++++ .../Drupal/Tests/Core/Theme/RegistryTest.php | 9 ++++++ 7 files changed, 106 insertions(+), 11 deletions(-) diff --git a/core/core.services.yml b/core/core.services.yml index cf9082c0d6a4..d723cd8ea9c7 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1092,7 +1092,9 @@ services: class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry theme.manager: class: Drupal\Core\Theme\ThemeManager - arguments: ['@app.root', '@theme.registry', '@theme.negotiator', '@theme.initialization', '@request_stack', '@module_handler'] + arguments: ['@app.root', '@theme.negotiator', '@theme.initialization', '@request_stack', '@module_handler'] + calls: + - [setThemeRegistry, ['@theme.registry']] theme.initialization: class: Drupal\Core\Theme\ThemeInitialization arguments: ['@app.root', '@theme_handler', '@state'] @@ -1101,6 +1103,8 @@ services: arguments: ['@app.root', '@cache.default', '@lock', '@module_handler', '@theme_handler', '@theme.initialization'] tags: - { name: needs_destruction } + calls: + - [setThemeManager, ['@theme.manager']] authentication: class: Drupal\Core\Authentication\AuthenticationManager tags: diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index a0b1f6473fab..5e450ab851e0 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -130,6 +130,13 @@ class Registry implements DestructableInterface { */ protected $themeHandler; + /** + * The theme manager. + * + * @var \Drupal\Core\Theme\ThemeManagerInterface + */ + protected $themeManager; + /** * Constructs a \Drupal\Core\Theme\Registry object. * @@ -158,6 +165,16 @@ public function __construct($root, CacheBackendInterface $cache, LockBackendInte $this->themeInitialization = $theme_initialization; } + /** + * Sets the theme manager. + * + * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager + * The theme manager. + */ + public function setThemeManager(ThemeManagerInterface $theme_manager) { + $this->themeManager = $theme_manager; + } + /** * Initializes a theme with a certain name. * @@ -173,7 +190,7 @@ protected function init($theme_name = NULL) { } // Unless instantiated for a specific theme, use globals. if (!isset($theme_name)) { - $this->theme = \Drupal::theme()->getActiveTheme(); + $this->theme = $this->themeManager->getActiveTheme(); } // Instead of the active theme, a specific theme was requested. else { @@ -326,9 +343,9 @@ protected function build() { // Finally, hooks provided by the theme itself. $this->processExtension($cache, $this->theme->getName(), 'theme', $this->theme->getName(), $this->theme->getPath()); - // Let modules alter the registry. + // Let modules and themes alter the registry. $this->moduleHandler->alter('theme_registry', $cache); - // @todo Do we want to allow themes to take part? + $this->themeManager->alterForTheme($this->theme, 'theme_registry', $cache); // @todo Implement more reduction of the theme registry entry. // Optimize the registry to not have empty arrays for functions. diff --git a/core/lib/Drupal/Core/Theme/ThemeManager.php b/core/lib/Drupal/Core/Theme/ThemeManager.php index a100374e95d0..6850fcb283f6 100644 --- a/core/lib/Drupal/Core/Theme/ThemeManager.php +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php @@ -62,8 +62,6 @@ class ThemeManager implements ThemeManagerInterface { * * @param string $root * The app root. - * @param \Drupal\Core\Theme\Registry $theme_registry - * The theme registry. * @param \Drupal\Core\Theme\ThemeNegotiatorInterface $theme_negotiator * The theme negotiator. * @param \Drupal\Core\Theme\ThemeInitialization $theme_initialization @@ -72,15 +70,27 @@ class ThemeManager implements ThemeManagerInterface { * The request stack. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */ - public function __construct($root, Registry $theme_registry, ThemeNegotiatorInterface $theme_negotiator, ThemeInitialization $theme_initialization, RequestStack $request_stack, ModuleHandlerInterface $module_handler) { + public function __construct($root, ThemeNegotiatorInterface $theme_negotiator, ThemeInitialization $theme_initialization, RequestStack $request_stack, ModuleHandlerInterface $module_handler) { $this->root = $root; $this->themeNegotiator = $theme_negotiator; - $this->themeRegistry = $theme_registry; $this->themeInitialization = $theme_initialization; $this->requestStack = $request_stack; $this->moduleHandler = $module_handler; } + /** + * Sets the theme registry. + * + * @param \Drupal\Core\Theme\Registry $theme_registry + * The theme registry. + * + * @return $this + */ + public function setThemeRegistry(Registry $theme_registry) { + $this->themeRegistry = $theme_registry; + return $this; + } + /** * {@inheritdoc} */ @@ -402,7 +412,7 @@ protected function initTheme(RouteMatchInterface $route_match = NULL) { * * @todo Should we cache some of these information? */ - public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { + public function alterForTheme(ActiveTheme $theme, $type, &$data, &$context1 = NULL, &$context2 = NULL) { // Most of the time, $type is passed as a string, so for performance, // normalize it to that. When passed as an array, usually the first item in // the array is a generic type, and additional items in the array are more @@ -419,7 +429,6 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { } $theme_keys = array(); - $theme = $this->getActiveTheme(); foreach ($theme->getBaseThemes() as $base) { $theme_keys[] = $base->getName(); } @@ -446,4 +455,12 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { } } + /** + * {@inheritdoc} + */ + public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { + $theme = $this->getActiveTheme(); + $this->alterForTheme($theme, $type, $data, $context1, $context2); + } + } diff --git a/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php index b88d8faee217..fdc633438b65 100644 --- a/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php +++ b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php @@ -69,6 +69,8 @@ public function setActiveTheme(ActiveTheme $active_theme); /** * Passes alterable variables to specific $theme_TYPE_alter() implementations. * + * It also invokes alter hooks for all base themes. + * * $theme specifies the theme name of the active theme and all its base * themes. * @@ -122,4 +124,24 @@ public function setActiveTheme(ActiveTheme $active_theme); */ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL); + /** + * Provides an alter hook for a specific theme. + * + * Similar to ::alter, it also invokes the alter hooks for the base themes. + * + * @param \Drupal\Core\Theme\ActiveTheme $theme + * A manually specified theme. + * @param string|array $type + * A string describing the type of the alterable $data. + * @param mixed $data + * The variable that will be passed to $theme_TYPE_alter() implementations + * @param mixed $context1 + * (optional) An additional variable that is passed by reference. + * @param mixed $context2 + * (optional) An additional variable that is passed by reference. + * + * @see ::alter + */ + public function alterForTheme(ActiveTheme $theme, $type, &$data, &$context1 = NULL, &$context2 = NULL); + } diff --git a/core/modules/system/src/Tests/Theme/RegistryTest.php b/core/modules/system/src/Tests/Theme/RegistryTest.php index 8b6cb0afb1df..22f0cde15ba2 100644 --- a/core/modules/system/src/Tests/Theme/RegistryTest.php +++ b/core/modules/system/src/Tests/Theme/RegistryTest.php @@ -23,7 +23,7 @@ class RegistryTest extends KernelTestBase { * * @var array */ - public static $modules = array('theme_test'); + public static $modules = array('theme_test', 'system'); protected $profile = 'testing'; /** @@ -72,8 +72,11 @@ public function testMultipleSubThemes() { $theme_handler->install(['test_basetheme', 'test_subtheme', 'test_subsubtheme']); $registry_subsub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subsubtheme'); + $registry_subsub_theme->setThemeManager(\Drupal::theme()); $registry_sub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subtheme'); + $registry_sub_theme->setThemeManager(\Drupal::theme()); $registry_base_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_basetheme'); + $registry_base_theme->setThemeManager(\Drupal::theme()); $preprocess_functions = $registry_subsub_theme->get()['theme_test_template_test']['preprocess functions']; $this->assertIdentical([ @@ -96,4 +99,20 @@ public function testMultipleSubThemes() { 'test_basetheme_preprocess_theme_test_template_test', ], $preprocess_functions); } + + /** + * Tests that the theme registry can be altered by themes. + */ + public function testThemeRegistryAlterByTheme() { + + /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */ + $theme_handler = \Drupal::service('theme_handler'); + $theme_handler->install(['test_theme']); + $theme_handler->setDefault('test_theme'); + + $registry = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_theme'); + $registry->setThemeManager(\Drupal::theme()); + $this->assertEqual('value', $registry->get()['theme_test_template_test']['variables']['additional']); + } + } diff --git a/core/modules/system/tests/themes/test_theme/test_theme.theme b/core/modules/system/tests/themes/test_theme/test_theme.theme index 8c74ccdf487b..951fd583f6a3 100644 --- a/core/modules/system/tests/themes/test_theme/test_theme.theme +++ b/core/modules/system/tests/themes/test_theme/test_theme.theme @@ -94,3 +94,10 @@ function test_theme_theme_test_function_suggestions__theme_override($variables) function test_theme_theme_test_function_suggestions__module_override($variables) { return 'Theme function overridden based on new theme suggestion provided by a module.'; } + +/** + * Implements hook_theme_registry_alter(). + */ +function test_theme_theme_registry_alter(&$registry) { + $registry['theme_test_template_test']['variables']['additional'] = 'value'; +} diff --git a/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php b/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php index 2365a25b64a5..4a9101d0b4df 100644 --- a/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php +++ b/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php @@ -59,6 +59,13 @@ class RegistryTest extends UnitTestCase { */ protected $themeInitialization; + /** + * The theme manager. + * + * @var \Drupal\Core\Theme\ThemeManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $themeManager; + /** * {@inheritdoc} */ @@ -70,6 +77,7 @@ protected function setUp() { $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); $this->themeHandler = $this->getMock('Drupal\Core\Extension\ThemeHandlerInterface'); $this->themeInitialization = $this->getMock('Drupal\Core\Theme\ThemeInitializationInterface'); + $this->themeManager = $this->getMock('Drupal\Core\Theme\ThemeManagerInterface'); $this->setupTheme(); } @@ -124,6 +132,7 @@ public function testGetRegistryForModule() { protected function setupTheme($theme_name = NULL) { $this->registry = new TestRegistry($this->root, $this->cache, $this->lock, $this->moduleHandler, $this->themeHandler, $this->themeInitialization, $theme_name); + $this->registry->setThemeManager($this->themeManager); } } -- GitLab