Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 297886

[meta] Avoid calling drupal_render() "early", wherever it is beneficial to do so build and return structured data instead

$
0
0

As part of the discussion from #1830588: Put the page title on the page array (or its replacement), remove drupal_set_title(), @moshe sums this up nicely:

Well, the guideline since D7 has been that you don't call drupal_render(). You are supposed to return render arrays from blocks and page callbacks and then kick off all rendering at the end with drupal_render_page(). I notice that we have been adding calls to drupal_render() instead of removing them in issues like #2006152: [meta] Don't call theme() directly anywhere outside drupal_render(). Lets try not muddy the render pipeline with more calls like that. We have to figure out a way to handle nested theme() calls without using drupal_render(). Or disallow nested theme() calls.

The issue mentioned by @moshe is trying to remove theme() calls (which are "worse" than drupal_render() calls), as part of a general API cleanup but the sentiment expressed by @moshe is valid in a more general sense - the more we can avoid "early rendering" render arrays into strings, regardless of the exact function doing the rendering, the better.

"Early rendering" introduces a few issues:

- Code is harder to read and write because you have to be mindful of and mentally track how arrays and render calls are interleaved
- It's harder for alters and other functions that want to process structured data to do their work on already-rendered strings than organised associative arrays. This is expecially damaging for the efforts to make variables in Twig templates "drillable".
- In certain situations it can be a waste of CPU, e.g. consider the case where we do the work to render a child element and a parent element has #access => FALSE
- Rendering elements can have "side effects" like introducing new javascript or CSS files into the page and this may not be appropriate if the early-rendered element ends up not being displayed in the page
- The more we scatter calls to functions like theme() and drupal_render() around core, the harder it is for core contributors to see what the effects of making a modification to one of these API functions will be in all situations
- Early rendering arrays that are used in attributes of other arrays lets us "stick our heads in the sand" rather than fix underlying incompatibilities between element configurations that are commonly used together

Of course, it's not as simple as just blindly returning arrays instead of strings everywhere that drupal_render() currently appears. Often there are good reasons why an early render is happening, either due to limitations in the Render API itself or limitations in the implementation of a particular element #type/#theme.

A common enough example of how this could happen is something like the following:

// Render array to build up a string commonly used as a description for other elements.
$foo = array(
  '#type' => 'foo',
  ...
  ...
);

// Render array that has a #description attribute that will throw an exception for anything other than a string.
$bar = array(
  '#type' => 'bar',
  '#description' => drupal_render($foo).
  ...
  ...
);
return $bar;

Here we see that unless the $bar element with the #description attribute (that, for the sake of this example, is blindly concatenated onto a string inside a theme function) is provided with some way to render #description arrays into strings (hopefully by calling drupal_render() during the element's processing phases before rendering) we have to "early render" $foo.

Another solution to this problem is to simply use the existing concept of "child elements" in render arrays. Depending on what $bar is trying to do, the following may or may not be an appropriate refactor that requires less structural change to the way #type 'bar' is implemented:

// Render array to build up a string commonly used as a description for other elements.
$foo = array(
  '#type' => 'foo',
  ...
  ...
);

// Render array that has a #description attribute that will throw an exception for anything other than a string.
$bar = array(
  '#type' => 'bar',
  'description' => $foo.
  ...
  ...
);
return $bar;

There are many (literally hundreds in core) calls to drupal_render() so we have a lot of work to do, but every little bit we clean up will make the API more coherent overall so we should just start filing issues and working through them - https://api.drupal.org/api/drupal/core%21includes%21common.inc/function/...


Viewing all articles
Browse latest Browse all 297886

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>