Commit 3cda8309 authored by alexpott's avatar alexpott

Issue #1886448 by dawehner, sun, Berdir, ParisLiakos: Rewrite the theme...

Issue #1886448 by dawehner, sun, Berdir, ParisLiakos: Rewrite the theme registry into a proper service.
parent ac495597
...@@ -641,6 +641,11 @@ services: ...@@ -641,6 +641,11 @@ services:
class: Zend\Feed\Writer\Extension\Threading\Renderer\Entry class: Zend\Feed\Writer\Extension\Threading\Renderer\Entry
feed.writer.wellformedwebrendererentry: feed.writer.wellformedwebrendererentry:
class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry
theme.registry:
class: Drupal\Core\Theme\Registry
arguments: ['@cache.cache', '@lock', '@module_handler']
tags:
- { name: needs_destruction }
authentication: authentication:
class: Drupal\Core\Authentication\AuthenticationManager class: Drupal\Core\Authentication\AuthenticationManager
authentication.cookie: authentication.cookie:
......
...@@ -410,6 +410,13 @@ function install_begin_request(&$install_state) { ...@@ -410,6 +410,13 @@ function install_begin_request(&$install_state) {
// implementation here. // implementation here.
$container->register('lock', 'Drupal\Core\Lock\NullLockBackend'); $container->register('lock', 'Drupal\Core\Lock\NullLockBackend');
$container
->register('theme.registry', 'Drupal\Core\Theme\Registry')
->addArgument(new Reference('cache.cache'))
->addArgument(new Reference('lock'))
->addArgument(new Reference('module_handler'))
->addTag('needs_destruction');
// Register a module handler for managing enabled modules. // Register a module handler for managing enabled modules.
$container $container
->register('module_handler', 'Drupal\Core\Extension\ModuleHandler'); ->register('module_handler', 'Drupal\Core\Extension\ModuleHandler');
......
This diff is collapsed.
...@@ -91,6 +91,10 @@ function _drupal_maintenance_theme() { ...@@ -91,6 +91,10 @@ function _drupal_maintenance_theme() {
$ancestor = $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), '_theme_load_offline_registry');
_drupal_theme_initialize($themes[$theme], array_reverse($base_theme));
// Prime the theme registry.
// @todo Remove global theme variables.
Drupal::service('theme.registry');
// These CSS files are normally added by system_page_build(), except // These CSS files are normally added by system_page_build(), except
// system.maintenance.css. When the database is inactive, it's not called so // system.maintenance.css. When the database is inactive, it's not called so
...@@ -98,13 +102,6 @@ function _drupal_maintenance_theme() { ...@@ -98,13 +102,6 @@ function _drupal_maintenance_theme() {
drupal_add_library('system', 'normalize'); drupal_add_library('system', 'normalize');
} }
/**
* Builds the registry when the site needs to bypass any database calls.
*/
function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
return _theme_build_registry($theme, $base_theme, $theme_engine);
}
/** /**
* Returns HTML for a list of maintenance tasks to perform. * Returns HTML for a list of maintenance tasks to perform.
* *
......
...@@ -458,6 +458,10 @@ function update_prepare_d8_bootstrap() { ...@@ -458,6 +458,10 @@ function update_prepare_d8_bootstrap() {
new Settings($settings); new Settings($settings);
$kernel = new DrupalKernel('update', drupal_classloader(), FALSE); $kernel = new DrupalKernel('update', drupal_classloader(), FALSE);
$kernel->boot(); $kernel->boot();
// Clear the D7 caches, to ensure that for example the theme_registry does not
// take part in the upgrade process.
Drupal::cache('cache')->deleteAll();
} }
/** /**
......
This diff is collapsed.
...@@ -8,16 +8,19 @@ ...@@ -8,16 +8,19 @@
namespace Drupal\Core\Utility; namespace Drupal\Core\Utility;
use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\CacheCollector;
use Drupal\Core\DestructableInterface;
use Drupal\Core\Lock\LockBackendInterface;
/** /**
* Builds the run-time theme registry. * Builds the run-time theme registry.
* *
* Extends CacheArray to allow the theme registry to be accessed as a * A cache collector to allow the theme registry to be accessed as a
* complete registry, while internally caching only the parts of the registry * complete registry, while internally caching only the parts of the registry
* that are actually in use on the site. On cache misses the complete * that are actually in use on the site. On cache misses the complete
* theme registry is loaded and used to update the run-time cache. * theme registry is loaded and used to update the run-time cache.
*/ */
class ThemeRegistry extends CacheArray { class ThemeRegistry extends CacheCollector implements DestructableInterface {
/** /**
* Whether the partial registry can be persisted to the cache. * Whether the partial registry can be persisted to the cache.
...@@ -38,35 +41,42 @@ class ThemeRegistry extends CacheArray { ...@@ -38,35 +41,42 @@ class ThemeRegistry extends CacheArray {
* *
* @param string $cid * @param string $cid
* The cid for the array being cached. * The cid for the array being cached.
* @param string $bin * @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The bin to cache the array. * The cache backend.
* @param \Drupal\Core\Lock\LockBackendInterface $lock
* The lock backend.
* @param array $tags * @param array $tags
* (optional) The tags to specify for the cache item. * (optional) The tags to specify for the cache item.
* @param bool $modules_loaded * @param bool $modules_loaded
* Whether all modules have already been loaded. * Whether all modules have already been loaded.
*/ */
function __construct($cid, $bin, $tags, $modules_loaded = FALSE) { function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $lock, $tags = array(), $modules_loaded = FALSE) {
$this->cid = $cid; $this->cid = $cid;
$this->bin = $bin; $this->cache = $cache;
$this->lock = $lock;
$this->tags = $tags; $this->tags = $tags;
$request = \Drupal::request(); $request = \Drupal::request();
$this->persistable = $modules_loaded && $request->isMethod('GET'); $this->persistable = $modules_loaded && $request->isMethod('GET');
if ($this->persistable && $cached = cache($this->bin)->get($this->cid)) { // @todo: Implement lazyload.
$data = $cached->data; $this->cacheLoaded = TRUE;
if ($this->persistable && $cached = $this->cache->get($this->cid)) {
$this->storage = $cached->data;
} }
else { else {
// If there is no runtime cache stored, fetch the full theme registry, // If there is no runtime cache stored, fetch the full theme registry,
// but then initialize each value to NULL. This allows offsetExists() // but then initialize each value to NULL. This allows offsetExists()
// to function correctly on non-registered theme hooks without triggering // to function correctly on non-registered theme hooks without triggering
// a call to resolveCacheMiss(). // a call to resolveCacheMiss().
$data = $this->initializeRegistry(); $this->storage = $this->initializeRegistry();
if ($this->persistable) { foreach (array_keys($this->storage) as $key) {
$this->set($data); $this->persist($key);
} }
// RegistryTest::testRaceCondition() ensures that the cache entry is
// written on the initial construction of the theme registry.
$this->updateCache();
} }
$this->storage = $data;
} }
/** /**
...@@ -77,58 +87,73 @@ function __construct($cid, $bin, $tags, $modules_loaded = FALSE) { ...@@ -77,58 +87,73 @@ function __construct($cid, $bin, $tags, $modules_loaded = FALSE) {
* initialized to NULL. * initialized to NULL.
*/ */
function initializeRegistry() { function initializeRegistry() {
$this->completeRegistry = theme_get_registry(); // @todo DIC this.
$this->completeRegistry = \Drupal::service('theme.registry')->get();
return array_fill_keys(array_keys($this->completeRegistry), NULL); return array_fill_keys(array_keys($this->completeRegistry), NULL);
} }
/** /**
* Overrides CacheArray::offsetExists(). * {@inheritdoc}
*/ */
public function offsetExists($offset) { public function has($key) {
// Since the theme registry allows for theme hooks to be requested that // Since the theme registry allows for theme hooks to be requested that
// are not registered, just check the existence of the key in the registry. // are not registered, just check the existence of the key in the registry.
// Use array_key_exists() here since a NULL value indicates that the theme // Use array_key_exists() here since a NULL value indicates that the theme
// hook exists but has not yet been requested. // hook exists but has not yet been requested.
return array_key_exists($offset, $this->storage); return array_key_exists($key, $this->storage);
} }
/** /**
* Overrides CacheArray::offsetGet(). * {@inheritdoc}
*/ */
public function offsetGet($offset) { public function get($key) {
// If the offset is set but empty, it is a registered theme hook that has // If the offset is set but empty, it is a registered theme hook that has
// not yet been requested. Offsets that do not exist at all were not // not yet been requested. Offsets that do not exist at all were not
// registered in hook_theme(). // registered in hook_theme().
if (isset($this->storage[$offset])) { if (isset($this->storage[$key])) {
return $this->storage[$offset]; return $this->storage[$key];
} }
elseif (array_key_exists($offset, $this->storage)) { elseif (array_key_exists($key, $this->storage)) {
return $this->resolveCacheMiss($offset); return $this->resolveCacheMiss($key);
} }
} }
/** /**
* Implements CacheArray::resolveCacheMiss(). * {@inheritdoc}
*/ */
public function resolveCacheMiss($offset) { public function resolveCacheMiss($key) {
if (!isset($this->completeRegistry)) { if (!isset($this->completeRegistry)) {
$this->completeRegistry = theme_get_registry(); $this->completeRegistry = \Drupal::service('theme.registry')->get();
} }
$this->storage[$offset] = $this->completeRegistry[$offset]; $this->storage[$key] = $this->completeRegistry[$key];
if ($this->persistable) { if ($this->persistable) {
$this->persist($offset); $this->persist($key);
} }
return $this->storage[$offset]; return $this->storage[$key];
} }
/** /**
* Overrides CacheArray::set(). * {@inheritdoc}
*/ */
public function set($data, $lock = TRUE) { protected function updateCache($lock = TRUE) {
$lock_name = $this->cid . ':' . $this->bin; if (!$this->persistable) {
if (!$lock || lock()->acquire($lock_name)) { return;
if ($cached = cache($this->bin)->get($this->cid)) { }
// @todo: Is the custom implementation necessary?
$data = array();
foreach ($this->keysToPersist as $offset => $persist) {
if ($persist) {
$data[$offset] = $this->storage[$offset];
}
}
if (empty($data)) {
return;
}
$lock_name = $this->cid . ':' . __CLASS__;
if (!$lock || $this->lock->acquire($lock_name)) {
if ($cached = $this->cache->get($this->cid)) {
// Use array merge instead of union so that filled in values in $data // Use array merge instead of union so that filled in values in $data
// overwrite empty values in the current cache. // overwrite empty values in the current cache.
$data = array_merge($cached->data, $data); $data = array_merge($cached->data, $data);
...@@ -137,10 +162,11 @@ public function set($data, $lock = TRUE) { ...@@ -137,10 +162,11 @@ public function set($data, $lock = TRUE) {
$registry = $this->initializeRegistry(); $registry = $this->initializeRegistry();
$data = array_merge($registry, $data); $data = array_merge($registry, $data);
} }
cache($this->bin)->set($this->cid, $data, CacheBackendInterface::CACHE_PERMANENT, $this->tags); $this->cache->set($this->cid, $data, CacheBackendInterface::CACHE_PERMANENT, $this->tags);
if ($lock) { if ($lock) {
lock()->release($lock_name); $this->lock->release($lock_name);
} }
} }
} }
} }
...@@ -35,17 +35,19 @@ public static function getInfo() { ...@@ -35,17 +35,19 @@ public static function getInfo() {
* Tests the behavior of the theme registry class. * Tests the behavior of the theme registry class.
*/ */
function testRaceCondition() { function testRaceCondition() {
$_SERVER['REQUEST_METHOD'] = 'GET'; \Drupal::request()->setMethod('GET');
$cid = 'test_theme_registry'; $cid = 'test_theme_registry';
// Directly instantiate the theme registry, this will cause a base cache // Directly instantiate the theme registry, this will cause a base cache
// entry to be written in __construct(). // entry to be written in __construct().
$registry = new ThemeRegistry($cid, 'cache', array('theme_registry' => TRUE), $this->container->get('module_handler')->isLoaded()); $cache = \Drupal::cache('cache');
$lock_backend = \Drupal::lock();
$registry = new ThemeRegistry($cid, $cache, $lock_backend, array('theme_registry' => TRUE), $this->container->get('module_handler')->isLoaded());
$this->assertTrue(cache()->get($cid), 'Cache entry was created.'); $this->assertTrue(cache()->get($cid), 'Cache entry was created.');
// Trigger a cache miss for an offset. // Trigger a cache miss for an offset.
$this->assertTrue($registry['theme_test_template_test'], 'Offset was returned correctly from the theme registry.'); $this->assertTrue($registry->get('theme_test_template_test'), 'Offset was returned correctly from the theme registry.');
// This will cause the ThemeRegistry class to write an updated version of // This will cause the ThemeRegistry class to write an updated version of
// the cache entry when it is destroyed, usually at the end of the request. // the cache entry when it is destroyed, usually at the end of the request.
// Before that happens, manually delete the cache entry we created earlier // Before that happens, manually delete the cache entry we created earlier
...@@ -53,15 +55,15 @@ function testRaceCondition() { ...@@ -53,15 +55,15 @@ function testRaceCondition() {
cache()->delete($cid); cache()->delete($cid);
// Destroy the class so that it triggers a cache write for the offset. // Destroy the class so that it triggers a cache write for the offset.
unset($registry); $registry->destruct();
$this->assertTrue(cache()->get($cid), 'Cache entry was created.'); $this->assertTrue(cache()->get($cid), 'Cache entry was created.');
// Create a new instance of the class. Confirm that both the offset // Create a new instance of the class. Confirm that both the offset
// requested previously, and one that has not yet been requested are both // requested previously, and one that has not yet been requested are both
// available. // available.
$registry = new ThemeRegistry($cid, 'cache', array('theme_registry' => TRUE)); $registry = new ThemeRegistry($cid, $cache, $lock_backend, array('theme_registry' => TRUE), $this->container->get('module_handler')->isLoaded());
$this->assertTrue($registry['theme_test_template_test'], 'Offset was returned correctly from the theme registry'); $this->assertTrue($registry->get('theme_test_template_test'), 'Offset was returned correctly from the theme registry');
$this->assertTrue($registry['theme_test_template_test_2'], 'Offset was returned correctly from the theme registry'); $this->assertTrue($registry->get('theme_test_template_test_2'), 'Offset was returned correctly from the theme registry');
} }
} }
...@@ -250,15 +250,9 @@ function testClassLoading() { ...@@ -250,15 +250,9 @@ function testClassLoading() {
* Tests drupal_find_theme_templates(). * Tests drupal_find_theme_templates().
*/ */
public function testFindThemeTemplates() { public function testFindThemeTemplates() {
$cache = array(); $registry = $this->container->get('theme.registry')->get();
$templates = drupal_find_theme_templates($registry, '.html.twig', drupal_get_path('theme', 'test_theme'));
// Prime the theme cache. $this->assertEqual($templates['node__1']['template'], 'node--1', 'Template node--1.tpl.twig was found in test_theme.');
foreach (\Drupal::moduleHandler()->getImplementations('theme') as $module) {
_theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
}
$templates = drupal_find_theme_templates($cache, '.html.twig', drupal_get_path('theme', 'test_theme'));
$this->assertEqual($templates['node__1']['template'], 'node--1', 'Template node--1.html.twig was found in test_theme.');
} }
/** /**
......
...@@ -41,11 +41,7 @@ function testTwigDebugMarkup() { ...@@ -41,11 +41,7 @@ function testTwigDebugMarkup() {
$this->rebuildContainer(); $this->rebuildContainer();
$this->resetAll(); $this->resetAll();
$cache = array(); $cache = $this->container->get('theme.registry')->get();
// Prime the theme cache.
foreach (\Drupal::moduleHandler()->getImplementations('theme') as $module) {
_theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
}
// Create array of Twig templates. // Create array of Twig templates.
$templates = drupal_find_theme_templates($cache, $extension, drupal_get_path('theme', 'test_theme')); $templates = drupal_find_theme_templates($cache, $extension, drupal_get_path('theme', 'test_theme'));
$templates += drupal_find_theme_templates($cache, $extension, drupal_get_path('module', 'node')); $templates += drupal_find_theme_templates($cache, $extension, drupal_get_path('module', 'node'));
......
...@@ -82,18 +82,24 @@ function testTwigCacheOverride() { ...@@ -82,18 +82,24 @@ function testTwigCacheOverride() {
->set('default', 'test_theme') ->set('default', 'test_theme')
->save(); ->save();
$cache = array(); // Unset the global variables, so \Drupal\Core\Theme\Registry::init() fires
// Prime the theme cache. // drupal_theme_initialize, which fills up the global variables properly
foreach (\Drupal::moduleHandler()->getImplementations('theme') as $module) { // and chosen the current active theme.
_theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); unset($GLOBALS['theme_info']);
} unset($GLOBALS['theme']);
// Reset the theme registry, so that the new theme is used.
$this->container->set('theme.registry', NULL);
// Load array of Twig templates. // Load array of Twig templates.
$templates = drupal_find_theme_templates($cache, $extension, drupal_get_path('theme', 'test_theme')); $registry = $this->container->get('theme.registry');
$registry->reset();
$templates = $registry->getRuntime();
// Get the template filename and the cache filename for // Get the template filename and the cache filename for
// theme_test.template_test.html.twig. // theme_test.template_test.html.twig.
$template_filename = $templates['theme_test_template_test']['path'] . '/' . $templates['theme_test_template_test']['template'] . $extension; $info = $templates->get('theme_test_template_test');
$template_filename = $info['path'] . '/' . $info['template'] . $extension;
$cache_filename = $this->container->get('twig')->getCacheFilename($template_filename); $cache_filename = $this->container->get('twig')->getCacheFilename($template_filename);
// Navigate to the page and make sure the template gets cached. // Navigate to the page and make sure the template gets cached.
......
...@@ -1362,7 +1362,7 @@ function hook_theme($existing, $type, $theme, $path) { ...@@ -1362,7 +1362,7 @@ function hook_theme($existing, $type, $theme, $path) {
* *
* The $theme_registry array is keyed by theme hook name, and contains the * The $theme_registry array is keyed by theme hook name, and contains the
* information returned from hook_theme(), as well as additional properties * information returned from hook_theme(), as well as additional properties
* added by _theme_process_registry(). * added by \Drupal\Core\Theme\Registry::processExtension().
* *
* For example: * For example:
* @code * @code
...@@ -1385,7 +1385,7 @@ function hook_theme($existing, $type, $theme, $path) { ...@@ -1385,7 +1385,7 @@ function hook_theme($existing, $type, $theme, $path) {
* The entire cache of theme registry information, post-processing. * The entire cache of theme registry information, post-processing.
* *
* @see hook_theme() * @see hook_theme()
* @see _theme_process_registry() * @see \Drupal\Core\Theme\Registry::processExtension()
*/ */
function hook_theme_registry_alter(&$theme_registry) { function hook_theme_registry_alter(&$theme_registry) {
// Kill the next/previous forum topic navigation links. // Kill the next/previous forum topic navigation links.
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\theme_test\EventSubscriber; namespace Drupal\theme_test\EventSubscriber;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
...@@ -14,7 +15,14 @@ ...@@ -14,7 +15,14 @@
/** /**
* Theme test subscriber for controller requests. * Theme test subscriber for controller requests.
*/ */
class ThemeTestSubscriber implements EventSubscriberInterface { class ThemeTestSubscriber extends ContainerAware implements EventSubscriberInterface {
/**
* The used container.
*
* @var \Symfony\Component\DependencyInjection\IntrospectableContainerInterface
*/
protected $container;
/** /**
* Generates themed output early in a page request. * Generates themed output early in a page request.
...@@ -36,10 +44,18 @@ public function onRequest(GetResponseEvent $event) { ...@@ -36,10 +44,18 @@ public function onRequest(GetResponseEvent $event) {
// returning output and theming the page as a whole. // returning output and theming the page as a whole.
$GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in a KernelEvents::REQUEST listener')); $GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in a KernelEvents::REQUEST listener'));
} }
}
/**
* Ensures that the theme registry was not initialized.
*/
public function onView(GetResponseEvent $event) {
$request = $event->getRequest();
$current_path = $request->attributes->get('_system_path');
if (strpos($current_path, 'user/autocomplete') === 0) { if (strpos($current_path, 'user/autocomplete') === 0) {
// Register a fake registry loading callback. If it gets called by if ($this->container->initialized('theme.registry')) {
// theme_get_registry(), the registry has not been initialized yet. throw new \Exception('registry initialized');
_theme_registry_callback('_theme_test_load_registry', array()); }
} }
} }
...@@ -48,6 +64,7 @@ public function onRequest(GetResponseEvent $event) { ...@@ -48,6 +64,7 @@ public function onRequest(GetResponseEvent $event) {
*/ */
static function getSubscribedEvents() { static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onRequest'); $events[KernelEvents::REQUEST][] = array('onRequest');
$events[KernelEvents::VIEW][] = array('onView', -1000);
return $events; return $events;
} }
......
...@@ -42,6 +42,9 @@ function theme_test_theme($existing, $type, $theme, $path) { ...@@ -42,6 +42,9 @@ function theme_test_theme($existing, $type, $theme, $path) {
$items['theme_test_function_template_override'] = array( $items['theme_test_function_template_override'] = array(
'variables' => array(), 'variables' => array(),
); );
$info['test_theme_not_existing_function'] = array(
'function' => 'test_theme_not_existing_function',
);
return $items; return $items;
} }
...@@ -76,13 +79,6 @@ function theme_test_menu() { ...@@ -76,13 +79,6 @@ function theme_test_menu() {
); );
return $items; return $items;
} }
/**
* Fake registry loading callback.
*/
function _theme_test_load_registry() {
print 'registry initialized';
return array();
}
/** /**
* Custom theme callback. * Custom theme callback.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Component\Utility\String; use Drupal\Component\Utility\String;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\Core\Theme\Registry;
use Drupal\views\Plugin\views\area\AreaPluginBase; use Drupal\views\Plugin\views\area\AreaPluginBase;
use Drupal\views\ViewExecutable; use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\PluginBase; use Drupal\views\Plugin\views\PluginBase;
...@@ -1756,54 +1757,21 @@ public function buildOptionsForm(&$form, &$form_state) { ...@@ -1756,54 +1757,21 @@ public function buildOptionsForm(&$form, &$form_state) {
} }
if (isset($GLOBALS['theme']) && $GLOBALS['theme'] == $this->theme) { if (isset($GLOBALS['theme']) && $GLOBALS['theme'] == $this->theme) {
$this->theme_registry = theme_get_registry(); $this->theme_registry = \Drupal::service('theme.registry')->get();
$theme_engine = $GLOBALS['theme_engine']; $theme_engine = $GLOBALS['theme_engine'];
} }
else { else {
$themes = list_themes(); $themes = list_themes();
$theme = $themes[$this->theme]; $theme = $themes[$this->theme];
// Find all our ancestor themes and put them in an array. // @see _drupal_theme_initialize()
$base_theme = array();
$ancestor = $this->theme;
while ($ancestor && isset($themes[$ancestor]->base_theme)) {
$ancestor = $themes[$ancestor]->base_theme;
$base_theme[] = $themes[$ancestor];
}
// The base themes should be initialized in the right order.
$base_theme = array_reverse($base_theme);
// This code is copied directly from _drupal_theme_initialize()
$theme_engine = NULL; $theme_engine = NULL;
// Initialize the theme.
if (isset($theme->engine)) { if (isset($theme->engine)) {
// Include the engine.
include_once DRUPAL_ROOT . '/' . $theme->owner;
$theme_engine = $theme->engine; $theme_engine = $theme->engine;
if (function_exists($theme_engine . '_init')) {
foreach ($base_theme as $base) {
call_user_func($theme_engine . '_init', $base);
}
call_user_func($theme_engine . '_init', $theme);
}
} }
else { $cache_theme = \Drupal::service('cache.theme');
// include non-engine theme files $this->theme_registry = new Registry($cache_theme, \Drupal::lock(), \Drupal::moduleHandler(), $theme->name);
foreach ($base_theme as $base) {
// Include the theme file or the engine.
if (!empty($base->owner)) {
include_once DRUPAL_ROOT . '/' . $base->owner;
}
}
// and our theme gets one too.
if (!empty($theme->owner)) {
include_once DRUPAL_ROOT . '/' . $theme->owner;
}
}
$this->theme_registry = _theme_load_registry($theme, $base_theme, $theme_engine);
} }
// If there's a theme engine involved, we also need to know its extension