From f8870768f5820566f1774f00dce66f8042a7f395 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Tue, 3 Mar 2020 10:24:11 +0000 Subject: [PATCH] =?UTF-8?q?Issue=20#3109480=20by=20longwave,=20catch,=20bn?= =?UTF-8?q?jmnm,=20xjm,=20lauriii,=20G=C3=A1bor=20Hojtsy:=20Properly=20dep?= =?UTF-8?q?recate=20theme=20functions=20for=20Drupal=2010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 4a70ba3774076ef81c41ffa784cee729fbf381f3) --- core/lib/Drupal/Core/Theme/Registry.php | 1 + .../modules/common_test/common_test.module | 18 -- .../theme_legacy_suggestions_test.inc} | 2 +- .../theme_legacy_suggestions_test.info.yml | 5 + .../theme_legacy_suggestions_test.module | 33 ++++ .../src/ThemeTestController.php | 40 ++++ .../theme_legacy_test/theme_legacy_test.inc | 13 ++ .../theme_legacy_test.info.yml | 5 + .../theme_legacy_test.module | 115 +++++++++++ .../theme_legacy_test.routing.yml | 22 +++ .../theme_suggestions_test.module | 26 --- .../theme_test/src/ThemeTestController.php | 26 --- .../templates/theme-test-foo.html.twig | 2 + ...eme-test-render-element-children.html.twig | 2 + .../tests/modules/theme_test/theme_test.inc | 7 - .../modules/theme_test/theme_test.module | 68 ------- .../modules/theme_test/theme_test.routing.yml | 23 --- .../src/Functional/Theme/ThemeLegacyTest.php | 83 ++++++++ .../Theme/ThemeSuggestionsAlterTest.php | 41 ---- .../tests/src/Functional/Theme/ThemeTest.php | 12 +- .../test_legacy_theme.info.yml | 6 + .../test_legacy_theme/test_legacy_theme.theme | 44 +++++ .../theme-test--suggestion.html.twig | 2 + .../tests/themes/test_theme/test_theme.theme | 43 ----- .../Core/Theme/RegistryLegacyTest.php | 70 +++++++ .../KernelTests/Core/Theme/RegistryTest.php | 9 - .../Tests/Core/Theme/RegistryLegacyTest.php | 180 ++++++++++++++++++ .../Drupal/Tests/Core/Theme/RegistryTest.php | 10 - 28 files changed, 626 insertions(+), 282 deletions(-) rename core/modules/system/tests/modules/{theme_suggestions_test/theme_suggestions_test.inc => theme_legacy_suggestions_test/theme_legacy_suggestions_test.inc} (74%) create mode 100644 core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.info.yml create mode 100644 core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.module create mode 100644 core/modules/system/tests/modules/theme_legacy_test/src/ThemeTestController.php create mode 100644 core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.inc create mode 100644 core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.info.yml create mode 100644 core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.module create mode 100644 core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.routing.yml create mode 100644 core/modules/system/tests/modules/theme_test/templates/theme-test-foo.html.twig create mode 100644 core/modules/system/tests/modules/theme_test/templates/theme-test-render-element-children.html.twig create mode 100644 core/modules/system/tests/src/Functional/Theme/ThemeLegacyTest.php create mode 100644 core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.info.yml create mode 100644 core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.theme create mode 100644 core/modules/system/tests/themes/test_theme/templates/theme-test--suggestion.html.twig create mode 100644 core/tests/Drupal/KernelTests/Core/Theme/RegistryLegacyTest.php create mode 100644 core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index c46f9109e7f..31b686bec0f 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -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"', diff --git a/core/modules/system/tests/modules/common_test/common_test.module b/core/modules/system/tests/modules/common_test/common_test.module index 040e40a4e4c..b14ceb7af85 100644 --- a/core/modules/system/tests/modules/common_test/common_test.module +++ b/core/modules/system/tests/modules/common_test/common_test.module @@ -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(). * diff --git a/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.inc b/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.inc similarity index 74% rename from core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.inc rename to core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.inc index efc0144551a..fc977ae7e3e 100644 --- a/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.inc +++ b/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.inc @@ -2,7 +2,7 @@ /** * @file - * Include file for testing theme suggestion hooks. + * Include file for testing theme suggestion hooks for legacy theme functions. */ /** diff --git a/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.info.yml b/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.info.yml new file mode 100644 index 00000000000..cf1f0aec775 --- /dev/null +++ b/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.info.yml @@ -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 diff --git a/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.module b/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.module new file mode 100644 index 00000000000..3986663b90c --- /dev/null +++ b/core/modules/system/tests/modules/theme_legacy_suggestions_test/theme_legacy_suggestions_test.module @@ -0,0 +1,33 @@ + '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'; +} diff --git a/core/modules/system/tests/modules/theme_legacy_test/src/ThemeTestController.php b/core/modules/system/tests/modules/theme_legacy_test/src/ThemeTestController.php new file mode 100644 index 00000000000..843858cc5f9 --- /dev/null +++ b/core/modules/system/tests/modules/theme_legacy_test/src/ThemeTestController.php @@ -0,0 +1,40 @@ + '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']; + } + +} diff --git a/core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.inc b/core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.inc new file mode 100644 index 00000000000..bbf74ffb74d --- /dev/null +++ b/core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.inc @@ -0,0 +1,13 @@ + '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.'; +} diff --git a/core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.routing.yml b/core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.routing.yml new file mode 100644 index 00000000000..ffc6b45776c --- /dev/null +++ b/core/modules/system/tests/modules/theme_legacy_test/theme_legacy_test.routing.yml @@ -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' diff --git a/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module b/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module index 5d4420270a8..b6d2f80cf2a 100644 --- a/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module +++ b/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module @@ -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'; -} diff --git a/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php b/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php index bd46aeaed90..2da8e8022dc 100644 --- a/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php +++ b/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php @@ -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. * diff --git a/core/modules/system/tests/modules/theme_test/templates/theme-test-foo.html.twig b/core/modules/system/tests/modules/theme_test/templates/theme-test-foo.html.twig new file mode 100644 index 00000000000..cd5a2650034 --- /dev/null +++ b/core/modules/system/tests/modules/theme_test/templates/theme-test-foo.html.twig @@ -0,0 +1,2 @@ +{# Output for Theme API test #} +{{ foo -}} diff --git a/core/modules/system/tests/modules/theme_test/templates/theme-test-render-element-children.html.twig b/core/modules/system/tests/modules/theme_test/templates/theme-test-render-element-children.html.twig new file mode 100644 index 00000000000..6a9d0fdf25f --- /dev/null +++ b/core/modules/system/tests/modules/theme_test/templates/theme-test-render-element-children.html.twig @@ -0,0 +1,2 @@ +{# Output for Theme API test #} +{{ element -}} diff --git a/core/modules/system/tests/modules/theme_test/theme_test.inc b/core/modules/system/tests/modules/theme_test/theme_test.inc index 1e0a7a654ad..050d3e98a0b 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.inc +++ b/core/modules/system/tests/modules/theme_test/theme_test.inc @@ -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(). */ diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module index 113676cbe9e..3763c3a18ad 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.module +++ b/core/modules/system/tests/modules/theme_test/theme_test.module @@ -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(). * diff --git a/core/modules/system/tests/modules/theme_test/theme_test.routing.yml b/core/modules/system/tests/modules/theme_test/theme_test.routing.yml index 6f880918f2f..1c12fef1995 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.routing.yml +++ b/core/modules/system/tests/modules/theme_test/theme_test.routing.yml @@ -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: diff --git a/core/modules/system/tests/src/Functional/Theme/ThemeLegacyTest.php b/core/modules/system/tests/src/Functional/Theme/ThemeLegacyTest.php new file mode 100644 index 00000000000..51de2eae461 --- /dev/null +++ b/core/modules/system/tests/src/Functional/Theme/ThemeLegacyTest.php @@ -0,0 +1,83 @@ +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.'); + } + +} diff --git a/core/modules/system/tests/src/Functional/Theme/ThemeSuggestionsAlterTest.php b/core/modules/system/tests/src/Functional/Theme/ThemeSuggestionsAlterTest.php index c521f58e50f..dcfdf150865 100644 --- a/core/modules/system/tests/src/Functional/Theme/ThemeSuggestionsAlterTest.php +++ b/core/modules/system/tests/src/Functional/Theme/ThemeSuggestionsAlterTest.php @@ -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. * diff --git a/core/modules/system/tests/src/Functional/Theme/ThemeTest.php b/core/modules/system/tests/src/Functional/Theme/ThemeTest.php index fe4471a2fa2..8058a752d28 100644 --- a/core/modules/system/tests/src/Functional/Theme/ThemeTest.php +++ b/core/modules/system/tests/src/Functional/Theme/ThemeTest.php @@ -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. * diff --git a/core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.info.yml b/core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.info.yml new file mode 100644 index 00000000000..d49d40105fd --- /dev/null +++ b/core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.info.yml @@ -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 diff --git a/core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.theme b/core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.theme new file mode 100644 index 00000000000..9802894955f --- /dev/null +++ b/core/modules/system/tests/themes/test_legacy_theme/test_legacy_theme.theme @@ -0,0 +1,44 @@ +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.'); + } + +} diff --git a/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php b/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php index 41f028336bf..bfc693f32d6 100644 --- a/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php +++ b/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php @@ -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.'); diff --git a/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php b/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php new file mode 100644 index 00000000000..0ee637fd39d --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php @@ -0,0 +1,180 @@ +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(); +} diff --git a/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php b/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php index f16b26f9312..c1f99629368 100644 --- a/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php +++ b/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php @@ -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.