Issue #3109480 by longwave, catch, bnjmnm, xjm, lauriii, Gábor Hojtsy: Properly deprecate theme functions for Drupal 10

(cherry picked from commit 4a70ba3774)
merge-requests/64/head
Alex Pott 2020-03-03 10:24:11 +00:00
parent 8274945514
commit f8870768f5
No known key found for this signature in database
GPG Key ID: 31905460D4A69276
28 changed files with 626 additions and 282 deletions

View File

@ -495,6 +495,7 @@ class Registry implements DestructableInterface {
// if the theme hook specifies a function callback instead, check to
// ensure the function actually exists.
if (isset($info['function'])) {
@trigger_error('Theme functions are deprecated in drupal:8.0.0 and are removed from drupal:10.0.0. Use Twig templates instead. See https://www.drupal.org/node/1831138', E_USER_DEPRECATED);
if (!function_exists($info['function'])) {
throw new \BadFunctionCallException(sprintf(
'Theme hook "%s" refers to a theme function callback that does not exist: "%s"',

View File

@ -121,27 +121,9 @@ function common_test_theme() {
'common_test_render_element' => [
'render element' => 'foo',
],
'common_test_empty' => [
'variables' => ['foo' => 'foo'],
'function' => 'theme_common_test_empty',
],
];
}
/**
* Provides a theme function for drupal_render().
*/
function theme_common_test_foo($variables) {
return $variables['foo'] . $variables['bar'];
}
/**
* Always returns an empty string.
*/
function theme_common_test_empty($variables) {
return '';
}
/**
* Implements MODULE_preprocess().
*

View File

@ -2,7 +2,7 @@
/**
* @file
* Include file for testing theme suggestion hooks.
* Include file for testing theme suggestion hooks for legacy theme functions.
*/
/**

View File

@ -0,0 +1,5 @@
name: 'Legacy theme functions suggestions test'
type: module
description: 'Support module for testing theme suggestions for legacy theme functions.'
package: Testing
version: VERSION

View File

@ -0,0 +1,33 @@
<?php
/**
* @file
* Support module for testing theme suggestions.
*
* @todo Remove in https://www.drupal.org/project/drupal/issues/3097889
*/
/**
* Implements hook_theme().
*/
function theme_legacy_suggestions_test_theme() {
$items['theme_suggestions_test_include'] = [
'file' => 'theme_legacy_suggestions_test.inc',
'function' => 'theme_theme_suggestions_test_include',
];
return $items;
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function theme_legacy_suggestions_test_theme_suggestions_theme_test_function_suggestions_alter(array &$suggestions, array $variables) {
$suggestions[] = 'theme_test_function_suggestions__module_override';
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function theme_legacy_suggestions_test_theme_suggestions_theme_test_suggestions_include_alter(array &$suggestions, array $variables, $hook) {
$suggestions[] = 'theme_suggestions_test_include';
}

View File

@ -0,0 +1,40 @@
<?php
namespace Drupal\theme_legacy_test;
use Drupal\Core\Controller\ControllerBase;
/**
* Controller routines for test routes for legacy theme functions.
*
* @todo Remove in https://www.drupal.org/project/drupal/issues/3097889
*/
class ThemeTestController extends ControllerBase {
/**
* A theme template that overrides a theme function.
*
* @return array
* Render array containing a theme.
*/
public function functionTemplateOverridden() {
return [
'#theme' => 'theme_test_function_template_override',
];
}
/**
* Menu callback for testing suggestion alter hooks with theme functions.
*/
public function functionSuggestionAlter() {
return ['#theme' => 'theme_test_function_suggestions'];
}
/**
* Menu callback for testing includes with suggestion alter hooks.
*/
public function suggestionAlterInclude() {
return ['#theme' => 'theme_test_suggestions_include'];
}
}

View File

@ -0,0 +1,13 @@
<?php
/**
* @file
* Include file for testing legacy theme functions.
*/
/**
* Returns HTML for the 'theme_test' theme hook used by tests.
*/
function theme_theme_test($variables) {
return 'Theme hook implementor=theme_theme_test(). Foo=' . $variables['foo'];
}

View File

@ -0,0 +1,5 @@
name: 'Legacy theme functions test'
type: module
description: 'Support module for testing legacy theme functions.'
package: Testing
version: VERSION

View File

@ -0,0 +1,115 @@
<?php
/**
* @file
* Test module for legacy theme functions.
*
* @todo Remove in https://www.drupal.org/project/drupal/issues/3097889
*/
/**
* Implements hook_theme().
*/
function theme_legacy_test_theme($existing, $type, $theme, $path) {
$items['theme_test'] = [
'file' => 'theme_legacy_test.inc',
'variables' => ['foo' => ''],
'function' => 'theme_theme_test',
];
$items['theme_test_function_suggestions'] = [
'variables' => [],
'function' => 'theme_theme_test_function_suggestions',
];
$items['theme_test_suggestions_include'] = [
'variables' => [],
'function' => 'theme_theme_test_suggestions_include',
];
$items['theme_test_foo'] = [
'variables' => ['foo' => NULL],
'function' => 'theme_theme_test_foo',
];
$items['theme_test_render_element_children'] = [
'render element' => 'element',
'function' => 'theme_theme_test_render_element_children',
];
$items['theme_test_function_template_override'] = [
'variables' => [],
'function' => 'theme_theme_test_function_template_override',
];
$info['test_theme_not_existing_function'] = [
'function' => 'test_theme_not_existing_function',
];
return $items;
}
/**
* Implements template_preprocess_HOOK() for theme_test_function_suggestions theme functions.
*/
function template_preprocess_theme_test_function_suggestions(&$variables) {
}
/**
* Theme function for hook theme_test_foo.
*/
function theme_theme_test_foo($variables) {
return $variables['foo'];
}
/**
* Theme function for hook theme_test_function_template_override.
*/
function theme_theme_test_function_template_override($variables) {
return 'theme_test_function_template_override test failed.';
}
/**
* Theme function for testing rendering of child elements via drupal_render().
*
* Theme hooks defining a 'render element' add an internal '#render_children'
* property. When this property is found, drupal_render() avoids calling
* the 'theme.manager' service 'render' method on the top-level element to
* prevent infinite recursion.
*
* @param array $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
*/
function theme_theme_test_render_element_children($variables) {
return \Drupal::service('renderer')->render($variables['element']);
}
/**
* Returns HTML for a theme function suggestion test.
*/
function theme_theme_test_function_suggestions($variables) {
return 'Original theme function.';
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function theme_legacy_test_theme_suggestions_theme_test_suggestion_provided(array $variables) {
return ['theme_test_suggestion_provided__foo'];
}
/**
* Implements hook_theme_suggestions_alter().
*/
function theme_legacy_test_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
\Drupal::messenger()
->addStatus(__FUNCTION__ . '() executed for ' . $hook . '.');
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function theme_legacy_test_theme_suggestions_theme_test_suggestions_alter(array &$suggestions, array $variables) {
\Drupal::messenger()->addStatus(__FUNCTION__ . '() executed.');
}
/**
* Returns HTML for a theme function include test.
*/
function theme_theme_test_suggestions_include($variables) {
return 'Original function before altering theme suggestions.';
}

View File

@ -0,0 +1,22 @@
theme_test.function_template_override:
path: '/theme-test/function-template-overridden'
options:
_custom_theme: 'test_theme'
defaults:
_controller: '\Drupal\theme_legacy_test\ThemeTestController::functionTemplateOverridden'
requirements:
_access: 'TRUE'
function_suggestion_alter:
path: '/theme-test/function-suggestion-alter'
defaults:
_controller: '\Drupal\theme_legacy_test\ThemeTestController::functionSuggestionAlter'
requirements:
_access: 'TRUE'
suggestion_alter_include:
path: '/theme-test/suggestion-alter-include'
defaults:
_controller: '\Drupal\theme_legacy_test\ThemeTestController::suggestionAlterInclude'
requirements:
_access: 'TRUE'

View File

@ -5,18 +5,6 @@
* Support module for testing theme suggestions.
*/
/**
* Implements hook_theme().
*/
function theme_suggestions_test_theme() {
$items['theme_suggestions_test_include'] = [
'file' => 'theme_suggestions_test.inc',
'variables' => [],
'function' => 'theme_theme_suggestions_test_include',
];
return $items;
}
/**
* Implements hook_theme_suggestions_alter().
*/
@ -35,23 +23,9 @@ function theme_suggestions_test_theme_suggestions_theme_test_suggestions_alter(a
$suggestions[] = 'theme_test_suggestions__module_override';
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function theme_suggestions_test_theme_suggestions_theme_test_function_suggestions_alter(array &$suggestions, array $variables) {
$suggestions[] = 'theme_test_function_suggestions__module_override';
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function theme_suggestions_test_theme_suggestions_theme_test_specific_suggestions_alter(array &$suggestions, array $variables) {
$suggestions[] = 'theme_test_specific_suggestions__variant__foo';
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function theme_suggestions_test_theme_suggestions_theme_test_suggestions_include_alter(array &$suggestions, array $variables, $hook) {
$suggestions[] = 'theme_suggestions_test_include';
}

View File

@ -10,18 +10,6 @@ use Symfony\Component\HttpFoundation\JsonResponse;
*/
class ThemeTestController extends ControllerBase {
/**
* A theme template that overrides a theme function.
*
* @return array
* Render array containing a theme.
*/
public function functionTemplateOverridden() {
return [
'#theme' => 'theme_test_function_template_override',
];
}
/**
* Adds stylesheets to test theme .info.yml property processing.
*
@ -112,20 +100,6 @@ class ThemeTestController extends ControllerBase {
return ['#theme' => 'theme_test_specific_suggestions__variant'];
}
/**
* Menu callback for testing suggestion alter hooks with theme functions.
*/
public function functionSuggestionAlter() {
return ['#theme' => 'theme_test_function_suggestions'];
}
/**
* Menu callback for testing includes with suggestion alter hooks.
*/
public function suggestionAlterInclude() {
return ['#theme' => 'theme_test_suggestions_include'];
}
/**
* Controller to ensure that no theme is initialized.
*

View File

@ -0,0 +1,2 @@
{# Output for Theme API test #}
{{ foo -}}

View File

@ -0,0 +1,2 @@
{# Output for Theme API test #}
{{ element -}}

View File

@ -5,13 +5,6 @@
* Include file for test module.
*/
/**
* Returns HTML for the 'theme_test' theme hook used by tests.
*/
function theme_theme_test($variables) {
return 'Theme hook implementor=theme_theme_test(). Foo=' . $variables['foo'];
}
/**
* Preprocesses variables for theme_theme_test().
*/

View File

@ -14,7 +14,6 @@ function theme_test_theme($existing, $type, $theme, $path) {
$items['theme_test'] = [
'file' => 'theme_test.inc',
'variables' => ['foo' => ''],
'function' => 'theme_theme_test',
];
$items['theme_test_template_test'] = [
'template' => 'theme_test.template_test',
@ -34,31 +33,14 @@ function theme_test_theme($existing, $type, $theme, $path) {
$items['theme_test_general_suggestions'] = [
'variables' => [],
];
$items['theme_test_function_suggestions'] = [
'variables' => [],
'function' => 'theme_theme_test_function_suggestions',
];
$items['theme_test_suggestions_include'] = [
'variables' => [],
'function' => 'theme_theme_test_suggestions_include',
];
$items['theme_test_foo'] = [
'variables' => ['foo' => NULL],
'function' => 'theme_theme_test_foo',
];
$items['theme_test_render_element'] = [
'render element' => 'elements',
];
$items['theme_test_render_element_children'] = [
'render element' => 'element',
'function' => 'theme_theme_test_render_element_children',
];
$items['theme_test_function_template_override'] = [
'variables' => [],
'function' => 'theme_theme_test_function_template_override',
];
$info['test_theme_not_existing_function'] = [
'function' => 'test_theme_not_existing_function',
];
$items['theme_test_preprocess_suggestions'] = [
'variables' => [
@ -95,26 +77,6 @@ function theme_test_page_bottom(array &$page_bottom) {
$page_bottom['theme_test_page_bottom'] = ['#markup' => 'theme test page bottom markup'];
}
/**
* Implements template_preprocess_HOOK() for theme_test_function_suggestions theme functions.
*/
function template_preprocess_theme_test_function_suggestions(&$variables) {
}
/**
* Theme function for hook theme_test_foo.
*/
function theme_theme_test_foo($variables) {
return $variables['foo'];
}
/**
* Theme function for hook theme_test_function_template_override.
*/
function theme_theme_test_function_template_override($variables) {
return 'theme_test_function_template_override test failed.';
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
@ -149,29 +111,6 @@ function template_preprocess_theme_test_render_element(&$variables) {
$variables['attributes']['data-variables-are-preprocessed'] = TRUE;
}
/**
* Theme function for testing rendering of child elements via drupal_render().
*
* Theme hooks defining a 'render element' add an internal '#render_children'
* property. When this property is found, drupal_render() avoids calling
* the 'theme.manager' service 'render' method on the top-level element to
* prevent infinite recursion.
*
* @param array $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
*/
function theme_theme_test_render_element_children($variables) {
return \Drupal::service('renderer')->render($variables['element']);
}
/**
* Returns HTML for a theme function suggestion test.
*/
function theme_theme_test_function_suggestions($variables) {
return 'Original theme function.';
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
@ -193,13 +132,6 @@ function theme_test_theme_suggestions_theme_test_suggestions_alter(array &$sugge
\Drupal::messenger()->addStatus(__FUNCTION__ . '() executed.');
}
/**
* Returns HTML for a theme function include test.
*/
function theme_theme_test_suggestions_include($variables) {
return 'Original function before altering theme suggestions.';
}
/**
* Implements hook_system_info_alter().
*

View File

@ -1,12 +1,3 @@
theme_test.function_template_override:
path: '/theme-test/function-template-overridden'
options:
_custom_theme: 'test_theme'
defaults:
_controller: '\Drupal\theme_test\ThemeTestController::functionTemplateOverridden'
requirements:
_access: 'TRUE'
theme_test.info_stylesheets:
path: '/theme-test/info/stylesheets'
defaults:
@ -83,20 +74,6 @@ specific_suggestion_alter:
requirements:
_access: 'TRUE'
function_suggestion_alter:
path: '/theme-test/function-suggestion-alter'
defaults:
_controller: '\Drupal\theme_test\ThemeTestController::functionSuggestionAlter'
requirements:
_access: 'TRUE'
suggestion_alter_include:
path: '/theme-test/suggestion-alter-include'
defaults:
_controller: '\Drupal\theme_test\ThemeTestController::suggestionAlterInclude'
requirements:
_access: 'TRUE'
theme_test.non_html:
path: '/theme-test/non-html'
defaults:

View File

@ -0,0 +1,83 @@
<?php
namespace Drupal\Tests\system\Functional\Theme;
use Drupal\Tests\BrowserTestBase;
/**
* Tests legacy theme functions.
*
* @group Theme
* @group legacy
*
* @todo Remove in https://www.drupal.org/project/drupal/issues/3097889
*/
class ThemeLegacyTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['theme_test', 'theme_legacy_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
protected function setUp() {
parent::setUp();
\Drupal::service('theme_installer')->install(['test_legacy_theme']);
}
/**
* Ensures a theme template can override a theme function.
*/
public function testFunctionOverride() {
$this->drupalGet('theme-test/function-template-overridden');
$this->assertText('Success: Template overrides theme function.', 'Theme function overridden by test_theme template.');
}
/**
* Tests that theme suggestion alter hooks work for theme functions.
*/
public function testThemeFunctionSuggestionsAlter() {
$this->drupalGet('theme-test/function-suggestion-alter');
$this->assertText('Original theme function.');
// Install test_theme and test that themes can alter theme suggestions.
$this->config('system.theme')
->set('default', 'test_legacy_theme')
->save();
$this->drupalGet('theme-test/function-suggestion-alter');
$this->assertText('Theme function overridden based on new theme suggestion provided by the test_legacy_theme theme.');
// Enable the theme_suggestions_test module to test modules implementing
// suggestions alter hooks.
\Drupal::service('module_installer')->install(['theme_legacy_suggestions_test']);
$this->resetAll();
$this->drupalGet('theme-test/function-suggestion-alter');
$this->assertText('Theme function overridden based on new theme suggestion provided by a module.');
}
/**
* Tests that theme suggestion alter hooks work with theme hook includes.
*/
public function testSuggestionsAlterInclude() {
// Check the original theme output.
$this->drupalGet('theme-test/suggestion-alter-include');
$this->assertText('Original function before altering theme suggestions.');
// Enable theme_suggestions_test module and make two requests to make sure
// the include file is always loaded. The file will always be included for
// the first request because the theme registry is being rebuilt.
\Drupal::service('module_installer')->install(['theme_legacy_suggestions_test']);
$this->resetAll();
$this->drupalGet('theme-test/suggestion-alter-include');
$this->assertText('Function suggested via suggestion alter hook found in include file.', 'Include file loaded for initial request.');
$this->drupalGet('theme-test/suggestion-alter-include');
$this->assertText('Function suggested via suggestion alter hook found in include file.', 'Include file loaded for second request.');
}
}

View File

@ -116,47 +116,6 @@ class ThemeSuggestionsAlterTest extends BrowserTestBase {
$this->assertTrue(strpos($raw_content, 'theme_test_specific_suggestions__variant') < strpos($raw_content, 'theme_test_specific_suggestions__variant__foo'), 'Specific theme call is added to the suggestions array before the suggestions alter hook.');
}
/**
* Tests that theme suggestion alter hooks work for theme functions.
*/
public function testThemeFunctionSuggestionsAlter() {
$this->drupalGet('theme-test/function-suggestion-alter');
$this->assertText('Original theme function.');
// Install test_theme and test that themes can alter theme suggestions.
$this->config('system.theme')
->set('default', 'test_theme')
->save();
$this->drupalGet('theme-test/function-suggestion-alter');
$this->assertText('Theme function overridden based on new theme suggestion provided by the test_theme theme.');
// Enable the theme_suggestions_test module to test modules implementing
// suggestions alter hooks.
\Drupal::service('module_installer')->install(['theme_suggestions_test']);
$this->resetAll();
$this->drupalGet('theme-test/function-suggestion-alter');
$this->assertText('Theme function overridden based on new theme suggestion provided by a module.');
}
/**
* Tests that theme suggestion alter hooks work with theme hook includes.
*/
public function testSuggestionsAlterInclude() {
// Check the original theme output.
$this->drupalGet('theme-test/suggestion-alter-include');
$this->assertText('Original function before altering theme suggestions.');
// Enable theme_suggestions_test module and make two requests to make sure
// the include file is always loaded. The file will always be included for
// the first request because the theme registry is being rebuilt.
\Drupal::service('module_installer')->install(['theme_suggestions_test']);
$this->resetAll();
$this->drupalGet('theme-test/suggestion-alter-include');
$this->assertText('Function suggested via suggestion alter hook found in include file.', 'Include file loaded for initial request.');
$this->drupalGet('theme-test/suggestion-alter-include');
$this->assertText('Function suggested via suggestion alter hook found in include file.', 'Include file loaded for second request.');
}
/**
* Tests execution order of theme suggestion alter hooks.
*

View File

@ -45,7 +45,7 @@ class ThemeTest extends BrowserTestBase {
drupal_theme_rebuild();
for ($i = 0; $i < 2; $i++) {
$this->drupalGet('theme-test/suggestion');
$this->assertText('Theme hook implementor=test_theme_theme_test__suggestion(). Foo=template_preprocess_theme_test', 'Theme hook suggestion ran with data available from a preprocess function for the base hook.');
$this->assertText('Theme hook implementor=theme-test--suggestion.html.twig. Foo=template_preprocess_theme_test', 'Theme hook suggestion ran with data available from a preprocess function for the base hook.');
}
}
@ -56,7 +56,7 @@ class ThemeTest extends BrowserTestBase {
$this->drupalGet('theme-test/priority');
// Ensure that the custom theme negotiator was not able to set the theme.
$this->assertNoText('Theme hook implementor=test_theme_theme_test__suggestion(). Foo=template_preprocess_theme_test', 'Theme hook suggestion ran with data available from a preprocess function for the base hook.');
$this->assertNoText('Theme hook implementor=theme-test--suggestion.html.twig. Foo=template_preprocess_theme_test', 'Theme hook suggestion ran with data available from a preprocess function for the base hook.');
}
/**
@ -141,14 +141,6 @@ class ThemeTest extends BrowserTestBase {
$this->assertText('Success: Template overridden.', 'Template overridden by defined \'template\' filename.');
}
/**
* Ensures a theme template can override a theme function.
*/
public function testFunctionOverride() {
$this->drupalGet('theme-test/function-template-overridden');
$this->assertText('Success: Template overrides theme function.', 'Theme function overridden by test_theme template.');
}
/**
* Tests that the page variable is not prematurely flattened.
*

View File

@ -0,0 +1,6 @@
name: 'Test legacy theme'
type: theme
description: 'Test theme to test deprecated functionality.'
version: VERSION
core: 8.x
base theme: test_theme

View File

@ -0,0 +1,44 @@
<?php
/**
* @file
* Theme to test functionality of legacy theme functions.
*
* @todo Remove in https://www.drupal.org/project/drupal/issues/3097889
*/
/**
* Tests a theme overriding a suggestion of a base theme hook.
*/
function test_legacy_theme_theme_test_preprocess_suggestions__kitten__meerkat($variables) {
return 'Theme hook implementor=test_theme_theme_test__suggestion(). Foo=' . $variables['foo'];
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function test_legacy_theme_theme_suggestions_theme_test_function_suggestions_alter(array &$suggestions, array $variables) {
// Theme alter hooks run after module alter hooks, so add this theme
// suggestion to the beginning of the array so that the suggestion added by
// the theme_suggestions_test module can be picked up when that module is
// enabled.
array_unshift($suggestions, 'theme_test_function_suggestions__' . 'theme_override');
}
/**
* Returns HTML for a theme function suggestion test.
*
* Implements the theme_test_function_suggestions__theme_override suggestion.
*/
function test_legacy_theme_theme_test_function_suggestions__theme_override($variables) {
return 'Theme function overridden based on new theme suggestion provided by the test_legacy_theme theme.';
}
/**
* Returns HTML for a theme function suggestion test.
*
* Implements the theme_test_function_suggestions__module_override suggestion.
*/
function test_legacy_theme_theme_test_function_suggestions__module_override($variables) {
return 'Theme function overridden based on new theme suggestion provided by a module.';
}

View File

@ -0,0 +1,2 @@
{# Output for Theme API test #}
Theme hook implementor=theme-test--suggestion.html.twig. Foo={{ foo }}

View File

@ -12,13 +12,6 @@ function test_theme_preprocess_twig_theme_test_php_variables(&$variables) {
$variables['php_values'] = _test_theme_twig_php_values();
}
/**
* Tests a theme overriding a suggestion of a base theme hook.
*/
function test_theme_theme_test__suggestion($variables) {
return 'Theme hook implementor=test_theme_theme_test__suggestion(). Foo=' . $variables['foo'];
}
/**
* Implements hook_element_info_alter().
*/
@ -75,35 +68,6 @@ function test_theme_theme_suggestions_theme_test_suggestions_alter(array &$sugge
array_unshift($suggestions, 'theme_test_suggestions__' . 'theme_override');
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function test_theme_theme_suggestions_theme_test_function_suggestions_alter(array &$suggestions, array $variables) {
// Theme alter hooks run after module alter hooks, so add this theme
// suggestion to the beginning of the array so that the suggestion added by
// the theme_suggestions_test module can be picked up when that module is
// enabled.
array_unshift($suggestions, 'theme_test_function_suggestions__' . 'theme_override');
}
/**
* Returns HTML for a theme function suggestion test.
*
* Implements the theme_test_function_suggestions__theme_override suggestion.
*/
function test_theme_theme_test_function_suggestions__theme_override($variables) {
return 'Theme function overridden based on new theme suggestion provided by the test_theme theme.';
}
/**
* Returns HTML for a theme function suggestion test.
*
* Implements the theme_test_function_suggestions__module_override suggestion.
*/
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().
*/
@ -111,13 +75,6 @@ function test_theme_theme_registry_alter(&$registry) {
$registry['theme_test_template_test']['variables']['additional'] = 'value';
}
/**
* Tests a theme overriding a suggestion of a base theme hook.
*/
function test_theme_theme_test_preprocess_suggestions__kitten__meerkat($variables) {
return 'Theme hook implementor=test_theme_theme_test__suggestion(). Foo=' . $variables['foo'];
}
/**
* Tests a theme overriding a default hook with a suggestion.
*

View File

@ -0,0 +1,70 @@
<?php
namespace Drupal\KernelTests\Core\Theme;
use Drupal\Core\Theme\Registry;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests legacy behavior of the ThemeRegistry class.
*
* @group Theme
* @group legacy
*
* @todo Remove in https://www.drupal.org/project/drupal/issues/3097889
*/
class RegistryLegacyTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['theme_test', 'system'];
protected $profile = 'testing';
/**
* Tests the theme registry with theme functions and multiple subthemes.
*
* @expectedDeprecation Theme functions are deprecated in drupal:8.0.0 and are removed from drupal:10.0.0. Use Twig templates instead. See https://www.drupal.org/node/1831138
*/
public function testMultipleSubThemes() {
$theme_handler = \Drupal::service('theme_handler');
\Drupal::service('module_installer')->install(['theme_legacy_test']);
\Drupal::service('theme_installer')->install(['test_basetheme']);
$registry_base_theme = new Registry($this->root, \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_basetheme');
$registry_base_theme->setThemeManager(\Drupal::theme());
$preprocess_functions = $registry_base_theme->get()['theme_test_function_suggestions']['preprocess functions'];
$this->assertSame([
'template_preprocess_theme_test_function_suggestions',
'test_basetheme_preprocess_theme_test_function_suggestions',
], $preprocess_functions, "Theme functions don't have template_preprocess but do have template_preprocess_HOOK");
}
/**
* Tests the theme registry with theme functions with suggestions.
*
* @expectedDeprecation Theme functions are deprecated in drupal:8.0.0 and are removed from drupal:10.0.0. Use Twig templates instead. See https://www.drupal.org/node/1831138
*/
public function testSuggestionPreprocessFunctions() {
$theme_handler = \Drupal::service('theme_handler');
\Drupal::service('theme_installer')->install(['test_legacy_theme']);
$registry_deprecated_theme = new Registry($this->root, \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_legacy_theme');
$registry_deprecated_theme->setThemeManager(\Drupal::theme());
$expected_preprocess_functions = [
'template_preprocess',
'theme_test_preprocess_theme_test_preprocess_suggestions',
'test_theme_preprocess_theme_test_preprocess_suggestions',
'test_theme_preprocess_theme_test_preprocess_suggestions__kitten',
];
$preprocess_functions = $registry_deprecated_theme->get()['theme_test_preprocess_suggestions__kitten__meerkat']['preprocess functions'];
$this->assertSame($expected_preprocess_functions, $preprocess_functions, 'Suggestion implemented as a function correctly inherits preprocess functions.');
}
}

View File

@ -97,12 +97,6 @@ class RegistryTest extends KernelTestBase {
'template_preprocess',
'test_basetheme_preprocess_theme_test_template_test',
], $preprocess_functions);
$preprocess_functions = $registry_base_theme->get()['theme_test_function_suggestions']['preprocess functions'];
$this->assertSame([
'template_preprocess_theme_test_function_suggestions',
'test_basetheme_preprocess_theme_test_function_suggestions',
], $preprocess_functions, "Theme functions don't have template_preprocess but do have template_preprocess_HOOK");
}
/**
@ -136,9 +130,6 @@ class RegistryTest extends KernelTestBase {
'test_theme_preprocess_theme_test_preprocess_suggestions__kitten',
];
$preprocess_functions = $registry_theme->get()['theme_test_preprocess_suggestions__kitten__meerkat']['preprocess functions'];
$this->assertSame($expected_preprocess_functions, $preprocess_functions, 'Suggestion implemented as a function correctly inherits preprocess functions.');
$preprocess_functions = $registry_theme->get()['theme_test_preprocess_suggestions__kitten__bearcat']['preprocess functions'];
$this->assertSame($expected_preprocess_functions, $preprocess_functions, 'Suggestion implemented as a template correctly inherits preprocess functions.');

View File

@ -0,0 +1,180 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Theme\RegistryLegacyTest.
*/
namespace Drupal\Tests\Core\Theme;
use Drupal\Core\Theme\ActiveTheme;
use Drupal\Core\Theme\Registry;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Theme\Registry
* @group Theme
* @group legacy
*
* @todo Remove in https://www.drupal.org/project/drupal/issues/3097889
*/
class RegistryLegacyTest extends UnitTestCase {
/**
* The tested theme registry.
*
* @var \Drupal\Tests\Core\Theme\TestRegistry
*/
protected $registry;
/**
* The mocked cache backend.
*
* @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $cache;
/**
* The mocked lock backend.
*
* @var \Drupal\Core\Lock\LockBackendInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $lock;
/**
* The mocked module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $moduleHandler;
/**
* The mocked theme handler.
*
* @var \Drupal\Core\Extension\ThemeHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $themeHandler;
/**
* The mocked theme initialization.
*
* @var \Drupal\Core\Theme\ThemeInitializationInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $themeInitialization;
/**
* The theme manager.
*
* @var \Drupal\Core\Theme\ThemeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $themeManager;
/**
* The list of functions that get_defined_functions() should provide.
*
* @var array
*/
public static $functions = [];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->cache = $this->createMock('Drupal\Core\Cache\CacheBackendInterface');
$this->lock = $this->createMock('Drupal\Core\Lock\LockBackendInterface');
$this->moduleHandler = $this->createMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->themeHandler = $this->createMock('Drupal\Core\Extension\ThemeHandlerInterface');
$this->themeInitialization = $this->createMock('Drupal\Core\Theme\ThemeInitializationInterface');
$this->themeManager = $this->createMock('Drupal\Core\Theme\ThemeManagerInterface');
$this->setupTheme();
}
/**
* {@inheritdoc}
*/
protected function tearDown() {
parent::tearDown();
static::$functions = [];
}
/**
* Tests getting legacy theme function registry data defined by a module.
*
* @expectedDeprecation Theme functions are deprecated in drupal:8.0.0 and are removed from drupal:10.0.0. Use Twig templates instead. See https://www.drupal.org/node/1831138
*/
public function testGetLegacyThemeFunctionRegistryForModule() {
$test_theme = new ActiveTheme([
'name' => 'test_legacy_theme',
'path' => 'core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.info.yml',
'engine' => 'twig',
'owner' => 'twig',
'stylesheets_remove' => [],
'libraries_override' => [],
'libraries_extend' => [],
'libraries' => [],
'extension' => '.twig',
'base_theme_extensions' => [],
]);
$this->themeManager->expects($this->once())
->method('getActiveTheme')
->willReturn($test_theme);
// Include the module and theme files so that hook_theme can be called.
include_once $this->root . '/core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.module';
$this->moduleHandler->expects($this->once())
->method('getImplementations')
->with('theme')
->will($this->returnValue(['theme_legacy_test']));
$this->moduleHandler->expects($this->atLeastOnce())
->method('getModuleList')
->willReturn([]);
$registry = $this->registry->get();
// Ensure that the registry entries from the module are found.
$this->assertArrayHasKey('theme_test', $registry);
$this->assertArrayHasKey('theme_test_function_suggestions', $registry);
$this->assertArrayHasKey('theme_test_foo', $registry);
$this->assertArrayHasKey('theme_test_render_element_children', $registry);
$this->assertArrayHasKey('theme_test_function_template_override', $registry);
$this->assertArrayNotHasKey('test_theme_not_existing_function', $registry);
$info = $registry['theme_test_function_suggestions'];
$this->assertEquals('module', $info['type']);
$this->assertEquals('core/modules/system/tests/modules/theme_legacy_test', $info['theme path']);
$this->assertEquals('theme_theme_test_function_suggestions', $info['function']);
$this->assertEquals([], $info['variables']);
}
protected function setupTheme() {
$this->registry = new TestRegistry($this->root, $this->cache, $this->lock, $this->moduleHandler, $this->themeHandler, $this->themeInitialization);
$this->registry->setThemeManager($this->themeManager);
}
}
class TestRegistry extends Registry {
protected function getPath($module) {
if ($module == 'theme_legacy_test') {
return 'core/modules/system/tests/modules/theme_legacy_test';
}
}
}
namespace Drupal\Core\Theme;
use Drupal\Tests\Core\Theme\RegistryLegacyTest;
/**
* Overrides get_defined_functions() with a configurable mock.
*/
function get_defined_functions() {
return RegistryLegacyTest::$functions ?: \get_defined_functions();
}

View File

@ -151,21 +151,11 @@ class RegistryTest extends UnitTestCase {
$this->assertArrayHasKey('theme_test_suggestion_provided', $registry);
$this->assertArrayHasKey('theme_test_specific_suggestions', $registry);
$this->assertArrayHasKey('theme_test_suggestions', $registry);
$this->assertArrayHasKey('theme_test_function_suggestions', $registry);
$this->assertArrayHasKey('theme_test_foo', $registry);
$this->assertArrayHasKey('theme_test_render_element', $registry);
$this->assertArrayHasKey('theme_test_render_element_children', $registry);
$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([], $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.