General developer forum

Proposal: Making template rendering less boilerplatey

 
Picture of Mark Johnson
Proposal: Making template rendering less boilerplatey
Core developersParticularly helpful MoodlersPlugin developers
There was a discussion in the DevJam session at MoodleMootIEUK last week about the best practice for creating output using templates.
One of the issues brought out was that there's a lot of "boilerplate" code required which doesn't do much, particularly around the requirement to create lots of renderer functions that look like this:

public function render_thing(plugin\output\thing $thing) {
$context = $thing->export_for_template($this);
return $this->render_from_template('plugin/thing', $context);
}

Assuming this is the simplest and most common use case of templatable objects, it seems to me that we can shortcut this by amending render_base::render() to look something like this (changes in bold):

    public function render(renderable $widget) {
$classname = get_class($widget);
// Strip namespaces.
$classparts = explode('\\', $classname);
$classname = array_pop($classparts);

// Remove _renderable suffixes
$classname = preg_replace('/_renderable$/', '', $classname);

$rendermethod = 'render_'.$classname;
if (method_exists($this, $rendermethod)) {
return $this->$rendermethod($widget);
}
if ($widget instanceof templatable) {
$component = array_shift($classparts);
if ($component) {
$template = $component . '/' . $classname;
$context = $widget->export_for_template($this);
return $this->render_from_template($template, $context);
}
}

throw new coding_exception('Can not render widget, renderer method ('.$rendermethod.') not found.');
}

This way, if you pass a renderable templateable object that's namespaced within your plugin, and there's a template with the same name as the class in your plugin, it will assume you want to do the simple case described above (there's probably an argument to be had about whether we lose any sub-namespaces when inferring the template name, as I've done here).

I've experimented with this a bit, it seems to work well.  If you want to do something more complicated, the render_thing() method is still given precedence, so defining one of those works too (i.e. all existing code will continue to work as expected).  Also, you can still override the render method (even if its not defined in the base renderer) or the template in a theme, so no change for theme authors.

Does anyone want to tell me why we shouldn't do this? smile

 
Average of ratings: Useful (4)
Picture of Michael Aherne
Re: Proposal: Making template rendering less boilerplatey
Core developersParticularly helpful MoodlersPlugin developers

+1 from me, it's a really elegant solution.

 
Average of ratings: -
Picture of Mark Johnson
Re: Proposal: Making template rendering less boilerplatey
Core developersParticularly helpful MoodlersPlugin developers

In the absence of any dissenting voices, I've created MDL-61869 with a initial stab at implementing this.

 
Average of ratings: Useful (2)