zendframework / zend-expressive-twigrenderer

Twig integration for Expressive
BSD 3-Clause "New" or "Revised" License
25 stars 14 forks source link

Ability to attach simple filters via configuration #58

Open edigu opened 5 years ago

edigu commented 5 years ago

Hello.

Few days ago I wanted to render a Money/Money instance in a twig template something like below:

<div> {{ customer.balance|money }} </div>

and needed to attach an additional custom filter into TwigEnvironment to achieve this goal. Altering the state of the environment somewhere else after it's creation bugged me a bit then decided to extend the whole factory which sounds also bad:

class MyTwigEnvironmentFactory extends ExpressiveTwigEnvironmentFactory
{
    public function __invoke(ContainerInterface $container): Environment
    {
        $environment = parent::__invoke($container);
        $environment->addFilter( ... );

        return $environment;

My actual filter implementation was so simple:

$filter = new TwigFilter('money', function (Money $money) {
    $currencies = ['EUR' => 2, 'USD' => 2];
    $formatter = new DecimalMoneyFormatter(new CurrencyList($currencies));

    return $formatter->format($money); // 
 })

Then I thought that I am literally doing a lot to achieve relatively small task and decided to introduce ability to attach simple filters using configuration.

This PR provides required functionality to attach custom filters into environment instance via configuration like following:

'twig' => [
    'filters' => [
         // user defined filters
         ['name' => 'greet', 'filter' => function($a) { return 'Hello ' . $a; } ],
         ['name' => 'mul', 'filter' => 'Math::multiply', 'options' => ['needs_context' => true] ],
         ['name' => 'money', 'filter' => ['MoneyHelper', 'format'] ],
         ['name' => 'uglify', 'filter' => \Lib\Twig\Filter\Uglify::class ],
     ],
],

I am open to hear opinions of other contributors to improve the implementation further.

Official docs for Twig Filters: https://twig.symfony.com/doc/2.x/advanced.html#filters

weierophinney commented 5 years ago

Until we review this, there's another way you can accomplish this that doesn't require extension: use a delegator factory on the Twig\Environment service, and add the filters there:

function (ContainerInterface $container, string $serviceName, callable $factory)
{
    $environment = $factory();
    $environment->addFilter(new TwigFilter(
        'money',
        function (Money $money) { /* ... */ }
    ));
    return $environment;
}
edigu commented 5 years ago

Thanks @weierophinney I just switched to delegator factory approach you've suggested and it worked nicely. It feels better than overriding the original factory in application code. But I still could not make sure which approach is more simpler/straightforward for everyone, creating a delegator factory or defining a few configuration options.

In any case documenting the way of introducing new twig filters makes sense since I needed to read whole TwigEnvironmentFactory code to understand and find correct place to inject my filters.

If delegator factories are way to go, I am also okay with ignoring this patch, even if it's working and %100 tested.

geerteltink commented 5 years ago

I'm not sure if we should add this.

First of all, with anonymous functions you can not cache your config anymore:

['name' => 'greet', 'filter' => function($a) { return 'Hello ' . $a; } ],

Also it's really easy to create a filter or use an existing one: https://github.com/twigphp/cssinliner-extension/blob/master/src/CssInlinerExtension.php

return [
    'dependencies' => [
        'factories' => [
            CssInlinerExtension::class => InvokableFactory::class,
        ],
    ],

    'twig' => [
        // ...
        'extensions' => [
            CssInlinerExtension::class,
        ],
    ],
];

Another example for a money filter: https://gist.github.com/xtreamwayz/7e54e28338772de765d9d478a6f52318

weierophinney commented 4 years ago

This repository has been closed and moved to mezzio/mezzio-twigrenderer; a new issue has been opened at https://github.com/mezzio/mezzio-twigrenderer/issues/1.

weierophinney commented 4 years ago

This repository has been moved to mezzio/mezzio-twigrenderer. If you feel that this patch is still relevant, please re-open against that repository, and reference this issue. To re-open, we suggest the following workflow: