Problem/Motivation
Coming from
β¨
Have a way to implement the a preprocess function per each SDC component (ideally in the same folder)
Active
. Although this is currently not actionable for SDC in core, i hope it can help with other decisions right now.
My gut feeling is that the current preprocess logic comes from a procedural and arrays mindset, and that more modern paradigms can help us in theming.
Currently, everything is (and has to be) prepared in render arrays, and the template can only assemble that pre-rendered items.
Sometimes this is not enough, and then some twig_extensions module adds some global function.
Using object methods in twig is strongly limited, and can only be extended via settings.php.
What if we inject services into templates like we do in the service container?
There are many possible services, but in the first round think: formatters.
While themes should not contain too much logic, this would be a nice way to hand over logic to themes (and power to themers).
Other issues this would solve
- Some modules like twig_tweak add global functions to each and every twig template. => By handing over that functions as service methods we can empower some themes while keeping sandboxing in place for others.
- Themes currently can construct and render arbitrary render arrays, which kills sandboxing and opens information disclosure security issues (e.g.: render an arbitrary view). => By handing over render array builder and renderer services we can solve that problem.
- Services can be altered. E.g. a URL or Date renderer may get improved markup.
- Sometimes theming depends on some data value, but the template only gets the data converted to render arrays, which leads to all kinds of kiten-killer solutions. => Here, the template gets the raw data, plus formatters or formatter factories.
In the end, this makes twig safer (via sandboxing), empower themers, and allow to alter services.
Proposed resolution
- Find and implement a way to whitelist object methods via an extension (i.e. without touching settings.php)
- Implement a way for a component template to require injected services (e.g. via frontmatter)
- Have some early adaptors work with that, add useful twig services, and document best practices
- Maybe deprecate other mechanisms, like global twig functions and maybe preprocess
Example
I doubt this is the best example, but the first that comes to my mind.
entity-component.twig
# FrontMatter yaml contains the analog of a service argument definition.
# Assume that twig.* services are whitelisted.
injected-services:
entity_display_reposirory: twig.entity_display_reposirory
formatter_factory: twig.date_formatter_factory
---
{# Render the entity like defined, but override the date formatter. #}
{% for field in entity %}
{% if field.name == 'field_data' %}
{{ formatter_factory.get('data', {'format': 'costum:Y-M-D'}).render(field) }}
{% else %}
{{ entity_display_reposirory.getFormatterForField(field).render(field) }}
{% endif %}
{% endfor %}