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

'#type' should be required in renderable arrays and should solely define the behaviour of drupal_render()

$
0
0

This is intended to be part of this meta issue #1843798: [meta] Refactor Render API.

Problem/Motivation

The usage of drupal_render() is hard to understand and use, isn't used consistently throughout core, its usage seems to contradict available documentation, it could be refactored to render simple elements faster and there's no easy/fast way to determine whether (outside of drupal_render()) a given array you have is a renderable array or "just an array".

Currently '#type' can be used to merge in some default renderable array properties http://drupal.org/node/930760:

When #type is declared for a render array, the default properties of the element type named are loaded through the use of hook_element_info().

But if we look at the documentation for hook_element_info() it says that this hook is for the Form API only, implying that '#type' is therefore only for the Form API too:

Allows modules to declare their own Form API element types and specify their default values.

This hook allows modules to declare their own form element types and to specify their default values. The values returned by this hook will be merged with the elements returned by hook_form() implementations and so can return defaults for any Form APIs keys in addition to those explicitly mentioned below.

The documentation for drupal_render() says nothing at all about what '#type' is supposed to do or that it's even an important key that can change the way that drupal_render() behaves.

Separately in drupal_render() we can declare '#theme' which defines the theme function responsible for rendering this array.

Renderable arrays can have pre and post render callbacks. Interestingly, for renderable arrays without a '#theme' set, there is no "render" phase, just "pre" and "post" but we're expected to produce #markup by the end of the "pre" phase, which is then concatenated to '#children' - see drupal_pre_render_link() for an example of this.

We also do things in core that aren't be explained by the documentation - why are we using '#type' => 'html_tag' to render style, meta and script tags with no '#theme' set? these aren't form elements and theme_html_tag() is called somehow.

So, when you want to build a renderable array for a arbitrary HTML tag or set of tags, you need to know:

A. Is this in a "form" context or not?
B. Is there a theme function that I need to declare in my renderable array to get the result that I want, and what is it?
C. Is this a special case non-'#theme', '#type' thing?

We also have a problem where because the expected behaviour of renderable arrays is split across the combination of '#type' and '#theme' or just '#markup' there's no easy/fast way to check if an array you have (outside of drupal_render) is actually just an associative array or is a special Drupal Renderable Array.

Instead of doing this:

if (isset($array['#type'])) { return drupal_render($array); }

We're stuck with things along these lines:
if (isset($array['#type']) || isset($array['#theme']) || isset($array'#markup') { return drupal_render($array) }

While that's annoying and a bit slower, it gets worse. Not enforcing a reliable "key" for all renderable arrays where you can say "I know this is a renderable array and I know what it is supposed to be" means that it's way harder to implement a consistent interface for preparing/altering what happens inside drupal_render(), you can't replace '#pre_render' and '#post_render' with a normal Drupal alter for example.

In addition, '#type' style renderable arrays can do things that '#theme' can't (have defaults merged in for example, and skip the theme system entirely) but '#theme' arrays with no '#type' have no extra "abilities".

Proposed resolution

I kind of want the patch on this issue to be as small as possible in the interest of keeping things simpler and not making it more complex.

- '#type' is not optional, it is required!
- if '#theme' is not set it is assumed to = '#type'
- if '#theme' is set and === FALSE then theme() is not called by drupal_render() - this could be achieved with hook_element_info()
- if '#type' and '#theme' are both set, '#theme' is passed to theme() as the first argument
- '#type' is documented as not being specific to the Form API and every type can register "defaults" with hook_element_info
- '#type' is a reserved key for arrays in Drupal, if an associative array has '#type' it is expected to be a valid renderable array
- We actually document what '#type' does for drupal_render()


Viewing all articles
Browse latest Browse all 293895

Trending Articles



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