StormoPL StormoPL - 4 months ago 27
YAML Question

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?

Answer

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]