code at http://cgit.drupalcode.org/sandbox-sun-1255586/?h=theme-init-2228093-dawehner2
Problem
Theme system is a mess.
If you interact with the theme functionality, you currently use one of the following ways:
- You use global $theme, ..., to get information about the current theme.
- You use _theme()/drupal_render() to generate some output.
This direct access only works, because the current theme happens to be manually initialized in various spots of the code-base. (@see LegacyRequestSubscriber)
Proposed resolution
Provide a service ('theme') which you can use to either render some output or get the current theme.
This is the canonical place for interaction.
In case you don't have the current theme initialized yet, the theme service asks the negotiator to get one and initializes (direct or indirect) that theme.
In order to do that, it needs a domain object of the current theme, which for example contains the theme info, stylesheets and libraries, as well as a list of the same domain object representing the parent themes (if any).
<?php
// @todo Find a better name.
interface ThemeServiceInterface {
/**
* @return string
*/
public function render($hook, $variables);
/**
* @return \Drupal\Core\Theme\ActiveTheme
*/
public function getActiveTheme();
/**
* Execute the alter hook on the current theme.
*/
public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL);
}
?>
The theme service has the following dependencies:
theme:
class: Drupal\Core\Theme\Theme
arguments: ['@theme_handler', '@theme.negotiator', '@theme.initialization', '@state']
State is used instead of cache to not rebuild the theme domain object all the time. (as in HEAD)
High-level service overview
ThemeHandler
only cares about managing theme extension objects, in the exact same way asModuleHandler
.The
Extension
objects are no longer manipulated with theme info/data.ThemeNegotiator
determines the theme to use for a particular request.ThemeInitialization
consultsThemeHandler
to retrieve the list of enabled themes, in order to instantiate theActiveTheme
domain object initialize the required theme engines.This is essentially
drupal_theme_initialize()
+_drupal_theme_initialize()
.ThemeHandler::rebuildThemeData()
+system_rebuild_theme_data()
is moved into this service.The
ActiveTheme
domain object is only built once for each theme and stored in state.This domain object consists of
global $theme_info
andglobal $base_theme_info
.The
Theme
service returns the initializedActiveTheme
domain object of the current/active theme for consumers.This replaces access to all
global $theme*
variables.
Notes
Theme::alter()
removes support for themes to participate in all alter hooks fromModuleHandler::alter()
.Instead,
Theme::alter()
will be specifically invoked manually for the few hooks in which themes are supposed to participate. That list is very limited; e.g.:hook_form_alter()
hook_page_alter()
hook_theme_suggestions_alter()
hook_theme_registry_alter()This plan should allow us to get rid of
$request->attributes->set('_theme_active')
inThemeNegotiator
, but we admit that we don't know how many things depend on that currently.