Issue #3488176 by nicxvan, godotislate: Convert system_theme to OOP and handle install time call

merge-requests/10188/head^2
catch 2024-11-21 16:40:29 +00:00
parent 175002ee4b
commit 42fda13321
7 changed files with 413 additions and 283 deletions

View File

@ -451,12 +451,6 @@ $ignoreErrors[] = [
'count' => 1,
'path' => __DIR__ . '/includes/theme.inc',
];
$ignoreErrors[] = [
// identifier: missingType.return
'message' => '#^Function drupal_common_theme\\(\\) has no return type specified\\.$#',
'count' => 1,
'path' => __DIR__ . '/includes/theme.inc',
];
$ignoreErrors[] = [
// identifier: missingType.return
'message' => '#^Function drupal_find_theme_templates\\(\\) has no return type specified\\.$#',

View File

@ -1801,156 +1801,3 @@ function _field_multiple_value_form_sort_helper($a, $b) {
$b_weight = (is_array($b) && isset($b['_weight']['#value']) ? $b['_weight']['#value'] : 0);
return $a_weight - $b_weight;
}
/**
* Provides theme registration for themes across .inc files.
*/
function drupal_common_theme() {
return [
// From theme.inc.
'html' => [
'render element' => 'html',
],
'page' => [
'render element' => 'page',
],
'page_title' => [
'variables' => ['title' => NULL],
],
'region' => [
'render element' => 'elements',
],
'time' => [
'variables' => ['timestamp' => NULL, 'text' => NULL, 'attributes' => []],
],
'datetime_form' => [
'render element' => 'element',
],
'datetime_wrapper' => [
'render element' => 'element',
],
'status_messages' => [
'variables' => ['status_headings' => [], 'message_list' => NULL],
],
'links' => [
'variables' => ['links' => [], 'attributes' => ['class' => ['links']], 'heading' => [], 'set_active_class' => FALSE],
],
'dropbutton_wrapper' => [
'variables' => ['children' => NULL],
],
'image' => [
// HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
// allows the alt attribute to be omitted in some cases. Therefore,
// default the alt attribute to an empty string, but allow code providing
// variables to image.html.twig templates to pass explicit NULL for it to
// be omitted. Usually, neither omission nor an empty string satisfies
// accessibility requirements, so it is strongly encouraged for code
// building variables for image.html.twig templates to pass a meaningful
// value for the alt variable.
// - https://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
// - https://www.w3.org/TR/xhtml1/dtds.html
// - http://dev.w3.org/html5/spec/Overview.html#alt
// The title attribute is optional in all cases, so it is omitted by
// default.
'variables' => ['uri' => NULL, 'width' => NULL, 'height' => NULL, 'alt' => '', 'title' => NULL, 'attributes' => [], 'sizes' => NULL, 'srcset' => [], 'style_name' => NULL],
],
'breadcrumb' => [
'variables' => ['links' => []],
],
'table' => [
'variables' => ['header' => NULL, 'rows' => NULL, 'footer' => NULL, 'attributes' => [], 'caption' => NULL, 'colgroups' => [], 'sticky' => FALSE, 'responsive' => TRUE, 'empty' => ''],
],
'tablesort_indicator' => [
'variables' => ['style' => NULL],
],
'mark' => [
'variables' => ['status' => MARK_NEW],
],
'item_list' => [
'variables' => ['items' => [], 'title' => '', 'list_type' => 'ul', 'wrapper_attributes' => [], 'attributes' => [], 'empty' => NULL, 'context' => []],
],
'feed_icon' => [
'variables' => ['url' => NULL, 'title' => NULL, 'attributes' => []],
],
'progress_bar' => [
'variables' => ['label' => NULL, 'percent' => NULL, 'message' => NULL],
],
'indentation' => [
'variables' => ['size' => 1],
],
// From theme.maintenance.inc.
'maintenance_page' => [
'render element' => 'page',
],
'install_page' => [
'render element' => 'page',
],
'maintenance_task_list' => [
'variables' => ['items' => NULL, 'active' => NULL, 'variant' => NULL],
],
'authorize_report' => [
'variables' => ['messages' => [], 'attributes' => []],
'includes' => ['core/includes/theme.maintenance.inc'],
'template' => 'authorize-report',
],
'pager' => [
'render element' => 'pager',
],
'menu' => [
'variables' => ['menu_name' => NULL, 'items' => [], 'attributes' => []],
],
'menu_local_task' => [
'render element' => 'element',
],
'menu_local_action' => [
'render element' => 'element',
],
'menu_local_tasks' => [
'variables' => ['primary' => [], 'secondary' => []],
],
// From form.inc.
'input' => [
'render element' => 'element',
],
'select' => [
'render element' => 'element',
],
'fieldset' => [
'render element' => 'element',
],
'details' => [
'render element' => 'element',
],
'radios' => [
'render element' => 'element',
],
'checkboxes' => [
'render element' => 'element',
],
'form' => [
'render element' => 'element',
],
'textarea' => [
'render element' => 'element',
],
'form_element' => [
'render element' => 'element',
],
'form_element_label' => [
'render element' => 'element',
],
'vertical_tabs' => [
'render element' => 'element',
],
'container' => [
'render element' => 'element',
],
// From field system.
'field' => [
'render element' => 'element',
],
'field_multiple_value_form' => [
'render element' => 'element',
],
];
}

View File

@ -391,9 +391,16 @@ class Registry implements DestructableInterface {
$cache = $cached->data;
}
else {
$this->moduleHandler->invokeAllWith('theme', function (callable $callback, string $module) use (&$cache) {
$this->processExtension($cache, $module, 'module', $module, $this->moduleList->getPath($module));
});
if (defined('MAINTENANCE_MODE') && constant('MAINTENANCE_MODE') === 'install') {
// System is still set here so preprocess can be updated in install.
$this->processExtension($cache, 'system', 'install', 'system', $this->moduleList->getPath('system'));
}
else {
$this->moduleHandler->invokeAllWith('theme', function (callable $callback, string $module) use (&$cache) {
$this->processExtension($cache, $module, 'module', $module, $this->moduleList->getPath($module));
});
}
// Only cache this registry if all modules are loaded.
if ($this->moduleHandler->isLoaded()) {
$this->cache->set("theme_registry:build:modules", $cache);
@ -464,12 +471,12 @@ class Registry implements DestructableInterface {
* The name of the module, theme engine, base theme engine, theme or base
* theme implementing hook_theme().
* @param string $type
* One of 'module', 'theme_engine', 'base_theme_engine', 'theme', or
* 'base_theme'. Unlike regular hooks that can only be implemented by
* modules, each of these can implement hook_theme(). This function is
* called in aforementioned order and new entries override older ones. For
* example, if a theme hook is both defined by a module and a theme, then
* the definition in the theme will be used.
* One of 'module', 'theme_engine', 'base_theme_engine', 'theme',
* 'base_theme', or 'install'. Unlike regular hooks that can only be
* implemented by modules, each of these can implement hook_theme(). This
* function is called in aforementioned order and new entries override
* older ones. For example, if a theme hook is both defined by a module and
* a theme, then the definition in the theme will be used.
* @param string $theme
* The actual name of theme, module, etc. that is being processed.
* @param string $path
@ -502,6 +509,12 @@ class Registry implements DestructableInterface {
if ($type === 'module') {
$result = $this->moduleHandler->invoke($name, 'theme', $args);
}
elseif ($type === 'install') {
$result = ThemeCommonElements::commonElements();
// Reset to module so that preprocess hooks are handled in install.
$type = 'module';
$args = [$cache, $type, $theme, $path];
}
else {
$function = $name . '_theme';
if (function_exists($function)) {

View File

@ -0,0 +1,252 @@
<?php
declare(strict_types=1);
namespace Drupal\Core\Theme;
/**
* Provide common theme render elements.
*/
class ThemeCommonElements {
/**
* Base theme array.
*
* @return array
* System theme array.
*/
public static function commonElements(): array {
return [
'html' => [
'render element' => 'html',
],
'page' => [
'render element' => 'page',
],
'page_title' => [
'variables' => [
'title' => NULL,
],
],
'region' => [
'render element' => 'elements',
],
'time' => [
'variables' => [
'timestamp' => NULL,
'text' => NULL,
'attributes' => [],
],
],
'datetime_form' => [
'render element' => 'element',
],
'datetime_wrapper' => [
'render element' => 'element',
],
'status_messages' => [
'variables' => [
'status_headings' => [],
'message_list' => NULL,
],
],
'links' => [
'variables' => [
'links' => [],
'attributes' => [
'class' => ['links'],
],
'heading' => [],
'set_active_class' => FALSE,
],
],
'dropbutton_wrapper' => [
'variables' => [
'children' => NULL,
],
],
'image' => [
// HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
// allows the alt attribute to be omitted in some cases. Therefore,
// default the alt attribute to an empty string, but allow code providing
// variables to image.html.twig templates to pass explicit NULL for it to
// be omitted. Usually, neither omission nor an empty string satisfies
// accessibility requirements, so it is strongly encouraged for code
// building variables for image.html.twig templates to pass a meaningful
// value for the alt variable.
// - https://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
// - https://www.w3.org/TR/xhtml1/dtds.html
// - http://dev.w3.org/html5/spec/Overview.html#alt
// The title attribute is optional in all cases, so it is omitted by
// default.
'variables' => [
'uri' => NULL,
'width' => NULL,
'height' => NULL,
'alt' => '',
'title' => NULL,
'attributes' => [],
'sizes' => NULL,
'srcset' => [],
'style_name' => NULL,
],
],
'breadcrumb' => [
'variables' => [
'links' => [],
],
],
'table' => [
'variables' => [
'header' => NULL,
'rows' => NULL,
'footer' => NULL,
'attributes' => [],
'caption' => NULL,
'colgroups' => [],
'sticky' => FALSE,
'responsive' => TRUE,
'empty' => '',
],
],
'tablesort_indicator' => [
'variables' => [
'style' => NULL,
],
],
'mark' => [
'variables' => [
'status' => MARK_NEW,
],
],
'item_list' => [
'variables' => [
'items' => [],
'title' => '',
'list_type' => 'ul',
'wrapper_attributes' => [],
'attributes' => [],
'empty' => NULL,
'context' => [],
],
],
'feed_icon' => [
'variables' => [
'url' => NULL,
'title' => NULL,
'attributes' => [],
],
],
'progress_bar' => [
'variables' => [
'label' => NULL,
'percent' => NULL,
'message' => NULL,
],
],
'indentation' => [
'variables' => ['size' => 1],
],
// From theme.maintenance.inc.
'maintenance_page' => [
'render element' => 'page',
],
'install_page' => [
'render element' => 'page',
],
'maintenance_task_list' => [
'variables' => [
'items' => NULL,
'active' => NULL,
'variant' => NULL,
],
],
'authorize_report' => [
'variables' => [
'messages' => [],
'attributes' => [],
],
'includes' => ['core/includes/theme.maintenance.inc'],
'template' => 'authorize-report',
],
'pager' => [
'render element' => 'pager',
],
'menu' => [
'variables' => [
'menu_name' => NULL,
'items' => [],
'attributes' => [],
],
],
'menu_local_task' => [
'render element' => 'element',
],
'menu_local_action' => [
'render element' => 'element',
],
'menu_local_tasks' => [
'variables' => [
'primary' => [],
'secondary' => [],
],
],
// From form.inc.
'input' => [
'render element' => 'element',
],
'select' => [
'render element' => 'element',
],
'fieldset' => [
'render element' => 'element',
],
'details' => [
'render element' => 'element',
],
'radios' => [
'render element' => 'element',
],
'checkboxes' => [
'render element' => 'element',
],
'form' => [
'render element' => 'element',
],
'textarea' => [
'render element' => 'element',
],
'form_element' => [
'render element' => 'element',
],
'form_element_label' => [
'render element' => 'element',
],
'vertical_tabs' => [
'render element' => 'element',
],
'container' => [
'render element' => 'element',
],
// From field system.
'field' => [
'render element' => 'element',
],
'field_multiple_value_form' => [
'render element' => 'element',
],
'off_canvas_page_wrapper' => [
'variables' => [
'children' => NULL,
],
],
'status_report_grouped' => [
'variables' => [
'grouped_requirements' => NULL,
'requirements' => NULL,
],
],
];
}
}

View File

@ -0,0 +1,138 @@
<?php
namespace Drupal\system\Hook;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Theme\ThemeCommonElements;
/**
* Hook implementations for system.
*/
class ThemeHook {
/**
* Implements hook_theme().
*/
#[Hook('theme')]
public function theme(): array {
$themeCommonElements = ThemeCommonElements::commonElements();
$systemTheme = [
// Normally theme suggestion templates are only picked up when they are in
// themes. We explicitly define theme suggestions here so that the block
// templates in core/modules/system/templates are picked up.
'block__system_branding_block' => [
'render element' => 'elements',
'base hook' => 'block',
],
'block__system_messages_block' => [
'base hook' => 'block',
],
'block__system_menu_block' => [
'render element' => 'elements',
'base hook' => 'block',
],
'system_themes_page' => [
'variables' => [
'theme_groups' => [],
'theme_group_titles' => [],
],
'file' => 'system.admin.inc',
],
'system_config_form' => [
'render element' => 'form',
],
'confirm_form' => [
'render element' => 'form',
],
'system_modules_details' => [
'render element' => 'form',
'file' => 'system.admin.inc',
],
'system_modules_uninstall' => [
'render element' => 'form',
'file' => 'system.admin.inc',
],
'status_report_page' => [
'variables' => [
'counters' => [],
'general_info' => [],
'requirements' => NULL,
],
],
'status_report' => [
'variables' => [
'grouped_requirements' => NULL,
'requirements' => NULL,
],
],
'status_report_counter' => [
'variables' => [
'amount' => NULL,
'text' => NULL,
'severity' => NULL,
],
],
'status_report_general_info' => [
'variables' => [
'drupal' => [],
'cron' => [],
'database_system' => [],
'database_system_version' => [],
'php' => [],
'php_memory_limit' => [],
'webserver' => [],
],
],
'admin_page' => [
'variables' => [
'blocks' => NULL,
],
'file' => 'system.admin.inc',
],
'admin_block' => [
'variables' => [
'block' => NULL,
'attributes' => [],
],
'file' => 'system.admin.inc',
],
'admin_block_content' => [
'variables' => [
'content' => NULL,
],
'file' => 'system.admin.inc',
],
'system_admin_index' => [
'variables' => [
'menu_items' => NULL,
],
'file' => 'system.admin.inc',
],
'entity_add_list' => [
'variables' => [
'bundles' => [],
'add_bundle_message' => NULL,
],
'template' => 'entity-add-list',
],
'system_security_advisories_fetch_error_message' => [
'file' => 'system.theme.inc',
'variables' => [
'error_message' => [],
],
],
'entity_page_title' => [
'variables' => [
'attributes' => [],
'title' => NULL,
'entity' => NULL,
'view_mode' => NULL,
],
],
];
return array_merge($themeCommonElements, $systemTheme);
}
}

View File

@ -40,120 +40,6 @@ const REGIONS_VISIBLE = 'visible';
*/
const REGIONS_ALL = 'all';
/**
* Implements hook_theme().
*/
function system_theme(): array {
return array_merge(drupal_common_theme(), [
// Normally theme suggestion templates are only picked up when they are in
// themes. We explicitly define theme suggestions here so that the block
// templates in core/modules/system/templates are picked up.
'block__system_branding_block' => [
'render element' => 'elements',
'base hook' => 'block',
],
'block__system_messages_block' => [
'base hook' => 'block',
],
'block__system_menu_block' => [
'render element' => 'elements',
'base hook' => 'block',
],
'system_themes_page' => [
'variables' => [
'theme_groups' => [],
'theme_group_titles' => [],
],
'file' => 'system.admin.inc',
],
'system_config_form' => [
'render element' => 'form',
],
'confirm_form' => [
'render element' => 'form',
],
'system_modules_details' => [
'render element' => 'form',
'file' => 'system.admin.inc',
],
'system_modules_uninstall' => [
'render element' => 'form',
'file' => 'system.admin.inc',
],
'status_report_page' => [
'variables' => [
'counters' => [],
'general_info' => [],
'requirements' => NULL,
],
],
'status_report' => [
'variables' => [
'grouped_requirements' => NULL,
'requirements' => NULL,
],
],
'status_report_grouped' => [
'variables' => [
'grouped_requirements' => NULL,
'requirements' => NULL,
],
],
'status_report_counter' => [
'variables' => ['amount' => NULL, 'text' => NULL, 'severity' => NULL],
],
'status_report_general_info' => [
'variables' => [
'drupal' => [],
'cron' => [],
'database_system' => [],
'database_system_version' => [],
'php' => [],
'php_memory_limit' => [],
'webserver' => [],
],
],
'admin_page' => [
'variables' => ['blocks' => NULL],
'file' => 'system.admin.inc',
],
'admin_block' => [
'variables' => ['block' => NULL, 'attributes' => []],
'file' => 'system.admin.inc',
],
'admin_block_content' => [
'variables' => ['content' => NULL],
'file' => 'system.admin.inc',
],
'system_admin_index' => [
'variables' => ['menu_items' => NULL],
'file' => 'system.admin.inc',
],
'entity_add_list' => [
'variables' => [
'bundles' => [],
'add_bundle_message' => NULL,
],
'template' => 'entity-add-list',
],
'off_canvas_page_wrapper' => [
'variables' => ['children' => NULL],
],
'system_security_advisories_fetch_error_message' => [
'file' => 'system.theme.inc',
'variables' => ['error_message' => []],
],
'entity_page_title' => [
'variables' => [
'attributes' => [],
'title' => NULL,
'entity' => NULL,
'view_mode' => NULL,
],
],
]);
}
/**
* Implements hook_hook_info().
*/

View File

@ -21,7 +21,7 @@ class ContentNegotiationRoutingTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['content_negotiation_test', 'path_alias'];
protected static $modules = ['content_negotiation_test', 'path_alias', 'system'];
/**
* {@inheritdoc}