diff --git a/core/core.services.yml b/core/core.services.yml index ff9ee96..99ae337 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -995,7 +995,7 @@ services: class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry theme.manager: class: Drupal\Core\Theme\ThemeManager - arguments: ['@theme.registry', '@theme.negotiator', '@theme.initialization', '@request_stack', '@module_handler'] + arguments: ['@app.root', '@theme.registry', '@theme.negotiator', '@theme.initialization', '@request_stack', '@module_handler'] theme.initialization: class: Drupal\Core\Theme\ThemeInitialization arguments: ['@app.root', '@theme_handler', '@state'] diff --git a/core/includes/common.inc b/core/includes/common.inc index 0397ee5..beb28b7 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -2383,7 +2383,7 @@ function drupal_pre_render_links($element) { * @deprecated as of Drupal 8.0.x. Use the 'renderer' service instead. */ function drupal_render_root(&$elements) { - return \Drupal::service('renderer')->render($elements, TRUE); + return \Drupal::service('renderer')->renderRoot($elements); } /** diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index a2d4e5a..5fb494e 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -14,7 +14,7 @@ use Drupal\Component\Utility\NestedArray; /** - * Converts a render array into a string. + * Turns a render array into a HTML string. */ class Renderer implements RendererInterface { @@ -58,6 +58,13 @@ public function __construct(ControllerResolverInterface $controller_resolver, Th /** * {@inheritdoc} */ + public function renderRoot(&$elements) { + return $this->render($elements, TRUE); + } + + /** + * {@inheritdoc} + */ public function render(&$elements, $is_root_call = FALSE) { static $stack; diff --git a/core/lib/Drupal/Core/Render/RendererInterface.php b/core/lib/Drupal/Core/Render/RendererInterface.php index 897ab19..1eded65 100644 --- a/core/lib/Drupal/Core/Render/RendererInterface.php +++ b/core/lib/Drupal/Core/Render/RendererInterface.php @@ -13,6 +13,27 @@ interface RendererInterface { /** + * Renders final HTML given a structured array tree. + * + * Calls ::render() in such a way that #post_render_cache callbacks are + * applied. + * + * Should therefore only be used in occasions where the final rendering is + * happening, just before sending a Response: + * - system internals that are responsible for rendering the final HTML + * - render arrays for non-HTML responses, such as feeds + * + * @param array $elements + * The structured array describing the data to be rendered. + * + * @return string + * The rendered HTML. + * + * @see ::render() + */ + public function renderRoot(&$elements); + + /** * Renders HTML given a structured array tree. * * Renderable arrays have two kinds of key/value pairs: properties and @@ -119,24 +140,24 @@ * of overrides as the value in #theme_wrappers array. * For example, if we have a render element as follows: * @code - * array( - * '#theme' => 'image', - * '#attributes' => array('class' => array('foo')), - * '#theme_wrappers' => array('container'), - * ); + * array( + * '#theme' => 'image', + * '#attributes' => array('class' => array('foo')), + * '#theme_wrappers' => array('container'), + * ); * @endcode * and we need to pass the class 'bar' as an attribute for 'container', we * can rewrite our element thus: * @code - * array( - * '#theme' => 'image', - * '#attributes' => array('class' => array('foo')), - * '#theme_wrappers' => array( - * 'container' => array( - * '#attributes' => array('class' => array('bar')), - * ), + * array( + * '#theme' => 'image', + * '#attributes' => array('class' => array('foo')), + * '#theme_wrappers' => array( + * 'container' => array( + * '#attributes' => array('class' => array('bar')), * ), - * ); + * ), + * ); * @endcode * - If this element has an array of #post_render functions defined, they * are called sequentially to modify the rendered #children. Unlike @@ -198,14 +219,14 @@ * The structured array describing the data to be rendered. * @param bool $is_root_call * (Internal use only.) Whether this is a recursive call or not. See - * drupal_render_root(). + * ::renderRoot(). * * @return string * The rendered HTML. * * @throws \LogicException - * If a root call to drupal_render() does not result in an empty stack, this - * indicates an erroneous drupal_render() root call (a root call within a + * If a root call to ::render() does not result in an empty stack, this + * indicates an erroneous ::render() root call (a root call within a * root call, which makes no sense). Therefore, a logic exception is thrown. * @throws \Exception * If a #pre_render callback throws an exception, it is caught to reset the @@ -216,7 +237,7 @@ * @see \Drupal\Core\Theme\ThemeManagerInterface::render() * @see drupal_process_states() * @see drupal_process_attached() - * @see drupal_render_root() + * @see ::renderRoot() */ public function render(&$elements, $is_root_call = FALSE); diff --git a/core/lib/Drupal/Core/Theme/ThemeManager.php b/core/lib/Drupal/Core/Theme/ThemeManager.php index e58bfed..a100374 100644 --- a/core/lib/Drupal/Core/Theme/ThemeManager.php +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php @@ -51,8 +51,17 @@ class ThemeManager implements ThemeManagerInterface { protected $requestStack; /** + * The app root. + * + * @var string + */ + protected $root; + + /** * Constructs a new ThemeManager object. * + * @param string $root + * The app root. * @param \Drupal\Core\Theme\Registry $theme_registry * The theme registry. * @param \Drupal\Core\Theme\ThemeNegotiatorInterface $theme_negotiator @@ -61,8 +70,10 @@ class ThemeManager implements ThemeManagerInterface { * The theme initialization. * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack * The request stack. + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */ - public function __construct(Registry $theme_registry, ThemeNegotiatorInterface $theme_negotiator, ThemeInitialization $theme_initialization, RequestStack $request_stack, ModuleHandlerInterface $module_handler) { + public function __construct($root, Registry $theme_registry, ThemeNegotiatorInterface $theme_negotiator, ThemeInitialization $theme_initialization, RequestStack $request_stack, ModuleHandlerInterface $module_handler) { + $this->root = $root; $this->themeNegotiator = $theme_negotiator; $this->themeRegistry = $theme_registry; $this->themeInitialization = $theme_initialization; @@ -116,7 +127,7 @@ public function setActiveTheme(ActiveTheme $active_theme) { /** * Generates themed output (internal use only). * - * @see ::render for the full documentation. + * @see \Drupal\Core\Render\RendererInterface::render(); */ protected function theme($hook, $variables = array()) { static $default_attributes; @@ -146,8 +157,9 @@ protected function theme($hook, $variables = array()) { // preprocess callbacks. $original_hook = $hook; - // If there's no implementation, check for more generic fallbacks. If there's - // still no implementation, log an error and return an empty string. + // If there's no implementation, check for more generic fallbacks. + // If there's still no implementation, log an error and return an empty + // string. if (!$theme_registry->has($hook)) { // Iteratively strip everything after the last '__' delimiter, until an // implementation is found. @@ -165,7 +177,8 @@ protected function theme($hook, $variables = array()) { } // There is no theme implementation for the hook passed. Return FALSE so // the function calling _theme() can differentiate between a hook that - // exists and renders an empty string and a hook that is not implemented. + // exists and renders an empty string and a hook that is not + // implemented. return FALSE; } } @@ -248,7 +261,7 @@ protected function theme($hook, $variables = array()) { // elsewhere. if (!empty($info['includes'])) { foreach ($info['includes'] as $include_file) { - include_once DRUPAL_ROOT . '/' . $include_file; + include_once $this->root . '/' . $include_file; } } @@ -256,11 +269,11 @@ protected function theme($hook, $variables = array()) { if (isset($info['base hook'])) { $base_hook = $info['base hook']; $base_hook_info = $theme_registry->get($base_hook); - // Include files required by the base hook, since its variable preprocessors - // might reside there. + // Include files required by the base hook, since its variable + // preprocessors might reside there. if (!empty($base_hook_info['includes'])) { foreach ($base_hook_info['includes'] as $include_file) { - include_once DRUPAL_ROOT . '/' . $include_file; + include_once $this->root . '/' . $include_file; } } // Replace the preprocess functions with those from the base hook. @@ -278,10 +291,10 @@ protected function theme($hook, $variables = array()) { } } // Allow theme preprocess functions to set $variables['#attached'] and use - // it like the #attached property on render arrays. In Drupal 8, this is the - // (only) officially supported method of attaching assets from preprocess - // functions. Assets attached here should be associated with the template - // that we're preprocessing variables for. + // it like the #attached property on render arrays. In Drupal 8, this is + // the (only) officially supported method of attaching assets from + // preprocess functions. Assets attached here should be associated with + // the template that we're preprocessing variables for. if (isset($variables['#attached'])) { $preprocess_attached = ['#attached' => $variables['#attached']]; drupal_render($preprocess_attached); @@ -299,7 +312,8 @@ protected function theme($hook, $variables = array()) { $render_function = 'twig_render_template'; $extension = '.html.twig'; - // The theme engine may use a different extension and a different renderer. + // The theme engine may use a different extension and a different + // renderer. $theme_engine = $active_theme->getEngine(); if (isset($theme_engine)) { if ($info['type'] != 'module') { @@ -314,15 +328,15 @@ protected function theme($hook, $variables = array()) { } // In some cases, a template implementation may not have had - // template_preprocess() run (for example, if the default implementation is - // a function, but a template overrides that default implementation). In - // these cases, a template should still be able to expect to have access to - // the variables provided by template_preprocess(), so we add them here if - // they don't already exist. We don't want the overhead of running - // template_preprocess() twice, so we use the 'directory' variable to - // determine if it has already run, which while not completely intuitive, - // is reasonably safe, and allows us to save on the overhead of adding some - // new variable to track that. + // template_preprocess() run (for example, if the default implementation + // is a function, but a template overrides that default implementation). + // In these cases, a template should still be able to expect to have + // access to the variables provided by template_preprocess(), so we add + // them here if they don't already exist. We don't want the overhead of + // running template_preprocess() twice, so we use the 'directory' variable + // to determine if it has already run, which while not completely + // intuitive, is reasonably safe, and allows us to save on the overhead of + // adding some new variable to track that. if (!isset($variables['directory'])) { $default_template_variables = array(); template_preprocess($default_template_variables, $hook, $info);