Services in Twig

Author: Matt
Monday, June 27 2016

In a recent project of ours, we needed to conditionally link a CSS file if it existed for a given tenant within a multi-tenant system.

We didn't want to have every controller or action have to check for this file and pass the results to Twig. Luckily for us, there's a better way!

Further to the above, it didn't feel right to have a controller doing this, it's not really the responsibility of the controller to handle such a thing. The controller's job is to handle requests, pass data off to relevant services / domain layers and then return the response generated based on that data.

That response could be rendered HTML, it could be XML, JSON etc. The functionality we're adding is specific to the HTML that's being rendered, so that's where the responsibility for handling this lies.

Referencing services in Twig to the rescue!

You can configure Twig to have services from the service container in Symfony usable within your templates. To do this, you use the same syntax as you do in other YAML configuration to reference the service:

# inside app/config/config.yml
twig:
    globals:
        customCssLocator: '@app.locator.css'

Once referenced, you can access it in your Twig templates and call methods on it like so:

{% customCssLocator.locateCustomCSS %}

The class we wrote would look on the filesystem for the relevant custom CSS stylesheet based on the tenant environment, and return the path (relative to the web root) for it, or null if it didn't find a stylesheet.

Once written, we can then use it in our templates like so:

{% set customStyling = customCssLocator.getCustomStylesheet %}
{% if customStyling is not null %}
    <link rel="stylesheet" type="text/css" href="{{ customStyling }}"/>
{% endif %}
3 useful tips for writing Alice fixtures Controlling whitespace in Twig