zenstruck/twig-service-bundle

Make functions, static methods, Symfony service methods available in your twig templates.

Fund package maintenance!
kbond

Installs: 1 607

Dependents: 0

Suggesters: 0

Security: 0

Stars: 6

Watchers: 2

Forks: 2

Open Issues: 1

Type:symfony-bundle

v1.5.0 2023-11-16 21:31 UTC

This package is auto-updated.

Last update: 2024-02-03 16:11:07 UTC


README

CI codecov

Making data from your app's services available in twig templates can be done by either:

  1. Injecting the service/data into the template when rendering.
  2. Creating a twig extension that has access to the service/data.

For #1, this isn't always a viable option (ie you need this data in your layout). With #2, there is a bit of boilerplate and if done incorrectly (ie not using a runtime or service proxy for heavy services), it could lead to performance issues.

This bundle provides an easy way to make functions, static methods, service methods, and even full service objects available in your twig templates.

Installation

composer require zenstruck/twig-service-bundle

Note

If not added automatically by symfony/flex, enable ZenstruckTwigServiceBundle.

Usage

Note

The output for the following functions/filters will be escaped. If your function\filter returns html that you don't want escaped, use the |raw filter.

Service Methods as Functions/Filters

You can mark any public method in your configured services with the #[AsTwigFunction] attribute to make them available within your twig templates with the fn() twig function/filter:

// ...
use Zenstruck\Twig\AsTwigFunction;

class SomeService
{
    // ...

    #[AsTwigFunction] // will be available as "someMethod" in twig
    public function someMethod($arg1, $arg2): string
    {
        // ...
    }

    #[AsTwigFunction('alias')] // will be available as "alias" in twig
    public function anotherMethod($arg1, $arg2): string
    {
        // ...
    }
}

In your twig template, use the fn() function/filter to call:

{# as a function: #}
{{ fn('someMethod', 'foo', 'bar') }}
{{ fn('alias', 'foo', 'bar') }}

{# as a filter: #}
{{ 'foo'|fn('someMethod', 'bar') }}
{{ 'foo'|fn('alias', 'bar') }}

Dynamic functions/filters are made available. The following is equivalent to above:

{# as a function: #}
{{ fn_someMethod('foo', 'bar') }}
{{ fn_alias('foo', 'bar') }}

{# as a filter: #}
{{ 'foo'|fn_someMethod('bar') }}
{{ 'foo'|fn_alias('bar') }}

User Defined as Functions/Filters

You can mark any of your custom functions with the #[AsTwigFunction] attribute to make them available within your twig templates with the fn() twig function\filter:

use Zenstruck\Twig\AsTwigFunction;

#[AsTwigFunction] // will be available as "some_function" in twig
function some_function($arg1, $arg2): string
{
    // ...
}

#[AsTwigFunction('alias')] // will be available as "alias" in twig
function another_function($arg1, $arg2): string
{
    // ...
}

In your twig template, use the fn() function/filter to call:

{# as a function: #}
{{ fn('some_function', 'foo', 'bar') }}
{{ fn('alias', 'foo', 'bar') }}

{# as a filter: #}
{{ 'foo'|fn('some_function', 'bar') }}
{{ 'foo'|fn('alias', 'bar') }}

Dynamic functions/filters are made available. The following is equivalent to above:

{# as a function: #}
{{ fn_some_function('foo', 'bar') }}
{{ fn_alias('foo', 'bar') }}

{# as a filter: #}
{{ 'foo'|fn_some_function('bar') }}
{{ 'foo'|fn_alias('bar') }}

3rd-Party Functions/Filters

If you need to make functions, static/service methods available in your twig templates for code you do not control (ie internal PHP functions/3rd party package), you can configure these in the bundle config:

zenstruck_twig_service:
    functions:
        - strlen # available as "fn_strlen()" in twig
        - [service.id, serviceMethod] # available as "fn_serviceMethod()" in twig
        - [Some\Class, somePublicStaticMethod] # available as "fn_somePublicStaticMethod()" in twig

    # use the array key to customize the name
    functions:
        len: strlen # available as "fn_len()" in twig
        custom: [service.id, serviceMethod] # available as "fn_custom()" in twig
        alias: [Some\Class, somePublicStaticMethod] # available as "fn_alias()" in twig

Service Function

Mark any service you'd like to make available in twig templates with the #[AsTwigService].

Note

While you can mark any service as a twig service, it is not recommended to mark services that have nothing to do with templating (ie repositories) as such. You can think of twig services as lightweight-lazy-twig-extension-functions whose purpose is to break up/simplify large custom twig extensions.

namespace App\Twig\Service;

// ...
use Zenstruck\Twig\AsTwigService;

#[AsTwigService(alias: 'posts')]
class PostService
{
    public function __construct(private PostRepository $repo)
    {
    }

    /**
     * @return Post[]
     */
    public function latestPosts(int $number = 10): array
    {
        return $this->repo->findLatestPosts($number);
    }
}

You're now ready to access the service in any twig template:

{% for post in service('posts').latestPosts(5) %}
    {# ... #}
{% endfor %}

Each service alias is made available as a dynamic function. The following is equivalent to above:

{% for post in service_posts().latestPosts(5) %}
    {# ... #}
{% endfor %}

Invokable Service Filters

You can turn any twig service into a twig filter by having it implement __invoke():

namespace App\Twig\Service;

// ...
use Zenstruck\Twig\AsTwigService;

#[AsTwigService(alias: 'image_transformer')]
class ImageTransformer
{
    public function __invoke(string $imageUrl, string ...$transformations): string
    {
        // adds transformation to url and returns new url
    }
}

In your template, use the service twig filter:

{{ url|service('image_transformer', 'square-200', 'watermark') }}

Each service alias is made available as a dynamic filter. The following is equivalent to above:

{{ url|service_image_transformer('square-200', 'watermark') }}

Parameter Function

You can access any service container parameter with the provided parameter() twig function:

{% for locale in parameter('kernel.enabled_locales') %}
    {# ... #}
{% endfor %}

zenstruck:twig-service:list Command

Use this command to list all functions/filters/services configured by this bundle and available in your twig templates.

Note

This command is only available when debug: true.

bin/console zenstruck:twig-service:list

Available Functions/Filters
---------------------------

 // As function: call with fn('{alias}', {...args}) or fn_{alias}({...args})

 // As filter: use as {value}|fn('{alias}', {...args}) or {value}|fn_{alias}({...args})

 ---------- ---------------------------------------------
  Alias      Callable
 ---------- ---------------------------------------------
  strlen     strlen
  generate   @router->generate()
 ---------- ---------------------------------------------

Available Services
------------------

 // Access via service('{alias}') or service_{alias}()

 // If invokable, use as {value}|service('{alias}', {...args}) or {value}|service_{alias}({...args})

 ------- -------------------- ------------
  Alias   Service              Invokable?
 ------- -------------------- ------------
  foo     App\SomeService      yes
  bar     App\AnotherService   no
 ------- -------------------- ------------

Full Default Bundle Configuration

zenstruck_twig_service:

    # Callables to make available with fn() twig function/filter
    functions:

        # Examples:
        0:                   strlen # available as "strlen"
        alias:               [Some\Class, somePublicStaticMethod] # available as "alias"