Symfony 7 — Twig extension for Stimulus values
EDIT:
As Jonathan pointed out, Stimulus has this functionality in stimulus_controller function, so this is more of exercise for Twig extensions 😄.
While using Stimulus with Symfony 7.1 and Twig templates I run into issue with Stimulus values.
I fount out that official Twig extension for Stimulus contains 3 Twig functions:
stimulus_controller
stimulus_target
stimulus_action
But there is no function for adding data attributes for Stimulus values. Luckily it is fairly easy to create our own Twig extensions, so here is the Stimulus Value Extension:
StimulusValueExtension.php:
<?php
namespace App\Twig\Extension;
use App\Twig\Runtime\StimulusValueRuntime;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class StimulusValueExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new TwigFunction('stimulus_value', [StimulusValueRuntime::class, 'stimulusValue']),
];
}
}
StimulusValueRuntime.php:
<?php
namespace App\Twig\Runtime;
use Twig\Extension\RuntimeExtensionInterface;
use Twig\Markup;
readonly class StimulusValueRuntime implements RuntimeExtensionInterface
{
public function stimulusValue(string $controllerName, string $valueName, mixed $value): Markup
{
$processedValue = $value;
if (!is_string($value)) {
$processedValue = json_encode($value);
}
$dataAttribute = sprintf("data-%s-%s-value='%s'", $controllerName, $valueName, $processedValue);
return new Markup($dataAttribute, 'UTF-8');
}
}
And usage:
<div
{{ stimulus_controller('controllerName') }}
{{ stimulus_value('controllerName', 'valueName', 'data') }}
>
...
</div>
The code can be also found here: https://gist.github.com/JakubPradeniak/5931c41b7b38a7bd7b63810cb714a109.
There is only one key point to keep in mind when creating Twig extensions like this — returning HTML, attributes or raw values in general — and itis the fact that Twig is processing and escaping everything we give it.
To output HTML or raw values properly we have to either use Twig'sraw
filter:
{{ some_func(…)|raw }}
or to return Twig Markup
— see return statement in Runtime class. This way we secure correct render of raw values without need of applying raw
filter.