Commit 08938d75 authored by catch's avatar catch
Browse files

Issue #2640962 by Berdir: Theme Registry does not support switching the active theme

(cherry picked from commit 16d9e20d)
parent 03248347
Loading
Loading
Loading
Loading
+23 −22
Changes for core/lib/Drupal/Core/Theme/Registry.php: 23 added lines, 22 removed lines.
Original line number Diff line number Diff line
@@ -40,7 +40,8 @@ class Registry implements DestructableInterface {
   * The complete theme registry.
   *
   * @var array
   *   An associative array keyed by theme hook names, whose values are
   *   An array of theme registries, keyed by the theme name. Each registry is
   *   an associative array keyed by theme hook names, whose values are
   *   associative arrays containing the aggregated hook definition:
   *   - type: The type of the extension the original theme hook originates
   *     from; e.g., 'module' for theme hook 'node' of Node module.
@@ -79,7 +80,7 @@ class Registry implements DestructableInterface {
   *   - process: An array of theme variable process callbacks to invoke
   *     before invoking the actual theme function or template.
   */
  protected $registry;
  protected $registry = [];

  /**
   * The cache backend to use for the complete theme registry data.
@@ -96,11 +97,11 @@ class Registry implements DestructableInterface {
  protected $moduleHandler;

  /**
   * The incomplete, runtime theme registry.
   * An array of incomplete, runtime theme registries, keyed by theme name.
   *
   * @var \Drupal\Core\Utility\ThemeRegistry
   * @var \Drupal\Core\Utility\ThemeRegistry[]
   */
  protected $runtimeRegistry;
  protected $runtimeRegistry = [];

  /**
   * Stores whether the registry was already initialized.
@@ -209,20 +210,20 @@ protected function init($theme_name = NULL) {
   */
  public function get() {
    $this->init($this->themeName);
    if (isset($this->registry)) {
      return $this->registry;
    if (isset($this->registry[$this->theme->getName()])) {
      return $this->registry[$this->theme->getName()];
    }
    if ($cache = $this->cache->get('theme_registry:' . $this->theme->getName())) {
      $this->registry = $cache->data;
      $this->registry[$this->theme->getName()] = $cache->data;
    }
    else {
      $this->registry = $this->build();
      $this->build();
      // Only persist it if all modules are loaded to ensure it is complete.
      if ($this->moduleHandler->isLoaded()) {
        $this->setCache();
      }
    }
    return $this->registry;
    return $this->registry[$this->theme->getName()];
  }

  /**
@@ -235,17 +236,17 @@ public function get() {
   */
  public function getRuntime() {
    $this->init($this->themeName);
    if (!isset($this->runtimeRegistry)) {
      $this->runtimeRegistry = new ThemeRegistry('theme_registry:runtime:' . $this->theme->getName(), $this->cache, $this->lock, array('theme_registry'), $this->moduleHandler->isLoaded());
    if (!isset($this->runtimeRegistry[$this->theme->getName()])) {
      $this->runtimeRegistry[$this->theme->getName()] = new ThemeRegistry('theme_registry:runtime:' . $this->theme->getName(), $this->cache, $this->lock, array('theme_registry'), $this->moduleHandler->isLoaded());
    }
    return $this->runtimeRegistry;
    return $this->runtimeRegistry[$this->theme->getName()];
  }

  /**
   * Persists the theme registry in the cache backend.
   */
  protected function setCache() {
    $this->cache->set('theme_registry:' . $this->theme->getName(), $this->registry, Cache::PERMANENT, array('theme_registry'));
    $this->cache->set('theme_registry:' . $this->theme->getName(), $this->registry[$this->theme->getName()], Cache::PERMANENT, array('theme_registry'));
  }

  /**
@@ -359,9 +360,9 @@ protected function build() {
        unset($cache[$hook]['preprocess functions']);
      }
    }
    $this->registry = $cache;
    $this->registry[$this->theme->getName()] = $cache;

    return $this->registry;
    return $this->registry[$this->theme->getName()];
  }

  /**
@@ -719,12 +720,12 @@ protected function postProcessExtension(array &$cache, ActiveTheme $theme) {
   */
  public function reset() {
    // Reset the runtime registry.
    if (isset($this->runtimeRegistry) && $this->runtimeRegistry instanceof ThemeRegistry) {
      $this->runtimeRegistry->clear();
    foreach ($this->runtimeRegistry as $runtime_registry) {
      $runtime_registry->clear();
    }
    $this->runtimeRegistry = NULL;
    $this->runtimeRegistry = [];

    $this->registry = NULL;
    $this->registry = [];
    Cache::invalidateTags(array('theme_registry'));
    return $this;
  }
@@ -733,8 +734,8 @@ public function reset() {
   * {@inheritdoc}
   */
  public function destruct() {
    if (isset($this->runtimeRegistry)) {
      $this->runtimeRegistry->destruct();
    foreach ($this->runtimeRegistry as $runtime_registry) {
      $runtime_registry->destruct();
    }
  }

+13 −0
Changes for core/modules/system/tests/themes/test_stable/test_stable.theme: 13 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

/**
 * @file
 * Test preprocess functions for theme test_stable.
 */

/**
 * Implements hook_preprocess_theme_test_render_element().
 */
function test_stable_preprocess_theme_test_render_element($variables) {
  // This is used for Drupal\Tests\Core\Theme\RegistryTest.
}
+32 −20
Changes for core/tests/Drupal/Tests/Core/Theme/RegistryTest.php: 32 added lines, 20 removed lines.
Original line number Diff line number Diff line
@@ -86,8 +86,7 @@ protected function setUp() {
   * Tests getting the theme registry defined by a module.
   */
  public function testGetRegistryForModule() {
    $this->setupTheme('test_theme');
    $this->registry->setTheme(new ActiveTheme([
    $test_theme = new ActiveTheme([
      'name' => 'test_theme',
      'path' => 'core/modules/system/tests/themes/test_theme/test_theme.info.yml',
      'engine' => 'twig',
@@ -98,11 +97,29 @@ public function testGetRegistryForModule() {
      'libraries' => [],
      'extension' => '.twig',
      'base_themes' => [],
    ]));
    ]);

    // Include the module so that hook_theme can be called.
    $test_stable = new ActiveTheme([
      'name' => 'test_stable',
      'path' => 'core/modules/system/tests/themes/test_stable/test_stable.info.yml',
      'engine' => 'twig',
      'owner' => 'twig',
      'stylesheets_remove' => [],
      'libraries_override' => [],
      'libraries_extend' => [],
      'libraries' => [],
      'extension' => '.twig',
      'base_themes' => [],
    ]);

    $this->themeManager->expects($this->exactly(2))
      ->method('getActiveTheme')
      ->willReturnOnConsecutiveCalls($test_theme, $test_stable);

    // Include the module and theme files so that hook_theme can be called.
    include_once $this->root . '/core/modules/system/tests/modules/theme_test/theme_test.module';
    $this->moduleHandler->expects($this->once())
    include_once $this->root . '/core/modules/system/tests/themes/test_stable/test_stable.theme';
    $this->moduleHandler->expects($this->exactly(2))
      ->method('getImplementations')
      ->with('theme')
      ->will($this->returnValue(array('theme_test')));
@@ -126,16 +143,24 @@ public function testGetRegistryForModule() {
    $this->assertArrayHasKey('theme_test_function_template_override', $registry);

    $this->assertArrayNotHasKey('test_theme_not_existing_function', $registry);
    $this->assertFalse(in_array('test_stable_preprocess_theme_test_render_element', $registry['theme_test_render_element']['preprocess functions']));

    $info = $registry['theme_test_function_suggestions'];
    $this->assertEquals('module', $info['type']);
    $this->assertEquals('core/modules/system/tests/modules/theme_test', $info['theme path']);
    $this->assertEquals('theme_theme_test_function_suggestions', $info['function']);
    $this->assertEquals(array(), $info['variables']);

    // The second call will initialize with the second theme. Ensure that this
    // returns a different object and the discovery for the second theme's
    // preprocess function worked.
    $other_registry = $this->registry->get();
    $this->assertNotSame($registry, $other_registry);
    $this->assertTrue(in_array('test_stable_preprocess_theme_test_render_element', $other_registry['theme_test_render_element']['preprocess functions']));
  }

  protected function setupTheme($theme_name = NULL) {
    $this->registry = new TestRegistry($this->root, $this->cache, $this->lock, $this->moduleHandler, $this->themeHandler, $this->themeInitialization, $theme_name);
  protected function setupTheme() {
    $this->registry = new TestRegistry($this->root, $this->cache, $this->lock, $this->moduleHandler, $this->themeHandler, $this->themeInitialization);
    $this->registry->setThemeManager($this->themeManager);
  }

@@ -143,23 +168,10 @@ protected function setupTheme($theme_name = NULL) {

class TestRegistry extends Registry {

  public function setTheme(ActiveTheme $theme) {
    $this->theme = $theme;
  }

  protected function init($theme_name = NULL) {
  }

  protected function getPath($module) {
    if ($module == 'theme_test') {
      return 'core/modules/system/tests/modules/theme_test';
    }
  }

  protected function listThemes() {
  }

  protected function initializeTheme() {
  }

}