Search code examples
symfonytwigyamltwig-extension

Integrating Symfony Routing and Twig using Symfony Twig Bridge


I use in my code Twig and Symfony routing which I would like to integrate with Twig using Symfony Twig Bridge.

I have them both installed and what I need to do is to add to Twig extensions Symfony\Bridge\Twig\Extension\RoutingExtension which requires Symfony\Component\Routing\Generator\UrlGenerator.

UrlGenerator requires 2 arguments:

  • routes collection
  • request context

So in my yaml services file I have:

    router:
    class: Symfony\Component\Routing\Router
    arguments:
        - '@yaml.file.loader'
        - '%routing.file%'
        - { 'cache_dir' : '%cache.dir%' }
        - '@request.context'

    twig:
    class: Twig_Environment
    calls:
        - ['addExtension', ['@twig.extensions.debug']]
        - ['addExtension', ['@twig.extensions.translate']]
        - ['addExtension', ['@twig.extensions.routing']]
    arguments:
        - '@twig.loader'
        - '%twig.options%'

    twig.extensions.routing:
    class: Symfony\Bridge\Twig\Extension\RoutingExtension
    public: false
    arguments:
        - '@twig.url.generator'

And finally UrlGenerator:

    twig.url.generator:
    class: Symfony\Component\Routing\Generator\UrlGenerator
    public: false
    arguments:
        - '@router'
        - '@request.context'

Unfortunatelly @router is not route collection type. It has method getRouteCollection which allows to get data required by UrlGenerator and it works if I add extension manually eg. from controller. But I don't want to split services definition between different files and prefer to keep them in yaml services definition.

So the question is: how to pass as an argument to UrlGenerator not the raw object Router but result of getRouteCollection?


Solution

  • There are multiple ways to do this:

    Using Symfony expression language

    If you have Symfony Expression Language component installed, you can do this in your service definition:

    twig.url.generator:
        class: Symfony\Component\Routing\Generator\UrlGenerator
        public: false
        arguments:
            - "@=service('router').getRouteCollection()"
            - "@request.context"
    

    Using factory

    If for some reason you don't want to use Symfony Expression Language, you can do it using a factory class which is responsible for instantiating your url generator.

    class UrlGeneratorFactory
    {
        private $router;
    
        private $requestContext;
    
        public function __construct($router, $requestContext)
        {
            $this->router = $router;
            $this->requestContext = $requestContext;
        }
    
        public function create()
        {
            return new UrlGenerator($this->router->getRouteCollection(), $this->requestContext);
        }
    }
    

    And in your yaml set url generator definition to:

    twig.url.generator.factory:
        class: UrlGeneratorFactory
        arguments: ["@router", "@request.context"]
    
    twig.url.generator:
        class:   Symfony\Component\Routing\Generator\UrlGenerator
        factory: ["@twig.url.generator.factory", create]