diff --git a/core/core.services.yml b/core/core.services.yml index c26834c..551d881 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -948,8 +948,8 @@ services: twig.loader: alias: twig.loader.filesystem twig.loader.filesystem: - class: Twig_Loader_Filesystem - arguments: ['%app.root%'] + class: Drupal\Core\Template\TwigThemeRegistryLoader + arguments: ['%app.root%', '@theme.registry'] element_info: alias: plugin.manager.element_info file.mime_type.guesser: diff --git a/core/lib/Drupal/Core/Template/TwigThemeRegistryLoader.php b/core/lib/Drupal/Core/Template/TwigThemeRegistryLoader.php new file mode 100644 index 0000000..ec6e17e --- /dev/null +++ b/core/lib/Drupal/Core/Template/TwigThemeRegistryLoader.php @@ -0,0 +1,131 @@ +setPaths($paths); + } + $this->themeRegistry = $theme_registry; + } + + /** + * Finds the path to the requested template. + * + * @param string $name + * The name of the template to load. + * + * @return string + * The path to the template. + * + * @throws Twig_Error_Loader + * Thrown if a template matching $name cannot be found. + */ + protected function findTemplate($name) { + // Go through the normal findTemplate() checks based on path and namespaced + // path. + if ($default = $this->findTemplateDefault($name)) { + return $default; + } + + // Allow for loading based on the Drupal theme registry. + $hook = str_replace('.html.twig', '', strtr($name, '-', '_')); + $theme_registry = $this->themeRegistry->getRuntime(); + + if ($theme_registry->has($hook)) { + $info = $theme_registry->get($hook); + if (isset($info['path'])) { + $path = $info['path'] . '/' . $name; + } + elseif (isset($info['template'])) { + $path = $info['template'] . '.html.twig'; + } + if (isset($path) && is_file($path)) { + return $this->cache[$name] = $path; + } + } + + throw new \Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]))); + } + + /** + * Finds the path to the requested template using standard methods. + * + * This is copied from Twig_Loader_Filesystem::findTemplate() and allows + * loading based on the path or namespaced path. The final throw has been + * removed and is in findTemplate() instead to allow additional loading based + * on the Drupal theme registry. + * + * @param string $name + * The name of the template to load. + * + * @return string + * The path to the template if one is found. + * + * @throws Twig_Error_Loader + * Thrown if namespace-related errors occur. + */ + protected function findTemplateDefault($name) { + $name = (string) $name; + + // Normalize name. + $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); + + if (isset($this->cache[$name])) { + return $this->cache[$name]; + } + + $this->validateName($name); + + $namespace = self::MAIN_NAMESPACE; + $shortname = $name; + if (isset($name[0]) && '@' == $name[0]) { + if (false === $pos = strpos($name, '/')) { + throw new \Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name)); + } + + $namespace = substr($name, 1, $pos - 1); + $shortname = substr($name, $pos + 1); + } + + if (!isset($this->paths[$namespace])) { + throw new \Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace)); + } + + foreach ($this->paths[$namespace] as $path) { + if (is_file($path . '/' . $shortname)) { + return $this->cache[$name] = $path . '/' . $shortname; + } + } + } + +} diff --git a/core/modules/system/src/Tests/Theme/TwigRegistryLoaderTest.php b/core/modules/system/src/Tests/Theme/TwigRegistryLoaderTest.php new file mode 100644 index 0000000..e62497b --- /dev/null +++ b/core/modules/system/src/Tests/Theme/TwigRegistryLoaderTest.php @@ -0,0 +1,70 @@ +twig = \Drupal::service('twig'); + } + + /** + * Checks to see if a value is a twig template. + */ + public function assertTwigTemplate($value, $message = '', $group = 'Other') { + $this->assertTrue($value instanceof \Twig_Template, $message, $group); + } + + /** + * Tests template discovery using the Drupal theme registry. + */ + public function testTemplateDiscovery() { + $this->assertTwigTemplate($this->twig->resolveTemplate('block.html.twig'), 'Found block.html.twig in block module.'); + } + + /** + * Tests template extension and includes using the Drupal theme registry. + */ + public function testTwigNamespaces() { + // Test the module-provided extend and insert templates. + $this->drupalGet('twig-theme-test/registry-loader'); + $this->assertText('This line is from twig_theme_test/templates/twig_registry_loader_test_extend.html.twig'); + $this->assertText('This line is from twig_theme_test/templates/twig_registry_loader_test_include.html.twig'); + + // Enable a theme that overrides the extend and insert templates to ensure + // they are picked up by the registry loader. + \Drupal::config('system.theme') + ->set('default', 'test_theme_twig_registry_loader') + ->save(); + $this->drupalGet('twig-theme-test/registry-loader'); + $this->assertText('This line is from test_theme_twig_registry_loader/templates/twig_registry_loader_test_extend.html.twig'); + $this->assertText('This line is from test_theme_twig_registry_loader/templates/twig_registry_loader_test_include.html.twig'); + } + +} diff --git a/core/modules/system/templates/block--system-branding-block.html.twig b/core/modules/system/templates/block--system-branding-block.html.twig index 4cf0f1a..f648773 100644 --- a/core/modules/system/templates/block--system-branding-block.html.twig +++ b/core/modules/system/templates/block--system-branding-block.html.twig @@ -1,4 +1,4 @@ -{% extends "@block/block.html.twig" %} +{% extends "block.html.twig" %} {# /** * @file diff --git a/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php b/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php index d454e5f..842a8e8 100644 --- a/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php +++ b/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php @@ -37,4 +37,11 @@ public function urlGeneratorRender() { ); } + /** + * Menu callback for testing the Twig registry loader. + */ + public function registryLoaderRender() { + return array('#theme' => 'twig_registry_loader_test'); + } + } diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test.html.twig new file mode 100644 index 0000000..8776f5e --- /dev/null +++ b/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test.html.twig @@ -0,0 +1,5 @@ +{% extends "twig_registry_loader_test_extend.html.twig" %} + +{% block content %} + {% include "twig_registry_loader_test_include.html.twig" %} +{% endblock %} diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test_extend.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test_extend.html.twig new file mode 100644 index 0000000..a5a5af1 --- /dev/null +++ b/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test_extend.html.twig @@ -0,0 +1,5 @@ +This line is from twig_theme_test/templates/twig_registry_loader_test_extend.html.twig + +{% block content %} +This text is in a block. +{% endblock %} diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test_include.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test_include.html.twig new file mode 100644 index 0000000..bb8c056 --- /dev/null +++ b/core/modules/system/tests/modules/twig_theme_test/templates/twig_registry_loader_test_include.html.twig @@ -0,0 +1 @@ +This line is from twig_theme_test/templates/twig_registry_loader_test_include.html.twig diff --git a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module index 0497c7b..046e994 100644 --- a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module +++ b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module @@ -19,6 +19,18 @@ function twig_theme_test_theme($existing, $type, $theme, $path) { 'variables' => array(), 'template' => 'twig_namespace_test', ); + $items['twig_registry_loader_test'] = array( + 'variables' => array(), + 'template' => 'twig_registry_loader_test', + ); + $items['twig_registry_loader_test_include'] = array( + 'variables' => array(), + 'template' => 'twig_registry_loader_test_include', + ); + $items['twig_registry_loader_test_extend'] = array( + 'variables' => array(), + 'template' => 'twig_registry_loader_test_extend', + ); $items['twig_raw_test'] = array( 'variables' => array('script' => ''), 'template' => 'twig-raw-test', diff --git a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml index 75b9bbb..77f1bf3 100644 --- a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml +++ b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml @@ -18,3 +18,10 @@ twig_theme_test_url_generator: _content: '\Drupal\twig_theme_test\TwigThemeTestController::urlGeneratorRender' requirements: _access: 'TRUE' + +twig_theme_test.registry_loader: + path: '/twig-theme-test/registry-loader' + defaults: + _content: '\Drupal\twig_theme_test\TwigThemeTestController::registryLoaderRender' + requirements: + _access: 'TRUE' diff --git a/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig_registry_loader_test_extend.html.twig b/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig_registry_loader_test_extend.html.twig new file mode 100644 index 0000000..7d5cb0e --- /dev/null +++ b/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig_registry_loader_test_extend.html.twig @@ -0,0 +1,5 @@ +This line is from test_theme_twig_registry_loader/templates/twig_registry_loader_test_extend.html.twig + +{% block content %} +This text is in a block. +{% endblock %} diff --git a/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig_registry_loader_test_include.html.twig b/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig_registry_loader_test_include.html.twig new file mode 100644 index 0000000..7097adf --- /dev/null +++ b/core/modules/system/tests/themes/test_theme_twig_registry_loader/templates/twig_registry_loader_test_include.html.twig @@ -0,0 +1 @@ +This line is from test_theme_twig_registry_loader/templates/twig_registry_loader_test_include.html.twig diff --git a/core/modules/system/tests/themes/test_theme_twig_registry_loader/test_theme_twig_registry_loader.info.yml b/core/modules/system/tests/themes/test_theme_twig_registry_loader/test_theme_twig_registry_loader.info.yml new file mode 100644 index 0000000..9ee01c5 --- /dev/null +++ b/core/modules/system/tests/themes/test_theme_twig_registry_loader/test_theme_twig_registry_loader.info.yml @@ -0,0 +1,5 @@ +name: 'Twig registry loader test' +type: theme +description: 'Support module for Twig registry loader testing.' +version: VERSION +core: 8.x diff --git a/core/themes/bartik/templates/block--system-branding-block.html.twig b/core/themes/bartik/templates/block--system-branding-block.html.twig index f6147a6..4a4b733 100644 --- a/core/themes/bartik/templates/block--system-branding-block.html.twig +++ b/core/themes/bartik/templates/block--system-branding-block.html.twig @@ -1,4 +1,4 @@ -{% extends "@block/block.html.twig" %} +{% extends "block.html.twig" %} {# /** * @file