1

In a Symfony2 project, I have created a service that implements Twig_ExtensionInterface so I can use it as a Twig filter, like {{ stuff|my_filter }}

In this service, I need to use the twig environnement so I could use twig templates for instance, so I injected it as one can do in a service :

in services.yml :

services:
    meta.twig.my_extension:
        class: Acme\GeneralBundle\Twig\MyExtension
        tags:
            - { name: twig.extension }
        arguments:
            twig: "@twig"

And so the service in itself looks like :

<?php

namespace Acme\GeneralBundle\Twig;

class MyExtension extends \Twig_Extension
{

    public function __construct($twig)
    {
        $this->twig = $twig;
    }

    public function getFilters()
    {
        return array(
            'my_filter' => new \Twig_Filter_Method($this, 'myFunction'),
        );
    }

    public function myFunction($text)
    {
       return $this->twig->render($someTemplate,$someArguments);
    }
}

And I can use it in a controller like that :

$myService = $this->container->get('Acme.twig.my_extension');
$text = $myService->myFunction($someValue);

But, of course, I get a CircularReference Error when doing so:

Circular reference detected for service "Acme.twig.my_extension", 
path: "Acme.twig.my_extension -> twig".

So, what is the best way to use twig->render() function inside a custom Twig Filter ?

Thanks a lot !

6
  • 1
    What version of symfony do you use? At 2.1 I do not see issue and such example as yours work without problems. You can try inject container instead of twig_env and lazy load twig. Commented Feb 1, 2013 at 22:19
  • 1
    I'm using version 2.1.8-DEV but this very example does not work. I understand that injecting the whole container is bad practice that's why I went this route... to no avail since effectively the twig environment seems to be "recursively injected" somehow. I could not find any literature on the web for a good solution though Commented Feb 1, 2013 at 23:06
  • Have you tried removing both the constructor of your extension and the arguments part on the services file? DIC should take care of that for you. Commented Feb 2, 2013 at 2:22
  • But then @DiegoAgulló how do I call the render() function of the Twig_Environment ? $this does not have such a method ... Commented Feb 2, 2013 at 13:18
  • I think you shouldn't need to do that in the first place. When defining a filter your method receives some parameters and returns a transformed string/int/whatever. Commented Feb 2, 2013 at 13:38

1 Answer 1

3

Twig_ExtensionInterface defines the initRuntime() method which accepts the twig environment as an argument. This method is called by twig while initialising the extension.

You've extended the Twig_Extension class, which already provides an empty implementation of this method. All you have to do is overwrite it and store a reference to the twig environment for future use.

<?php

namespace Acme\GeneralBundle\Twig;

class MyExtension extends \Twig_Extension
{
    private $environment = null;

    public function initRuntime(\Twig_Environment $environment)
    {
        $this->environment = $environment;
    }

    public function getFilters()
    {
        return array(
            'my_filter' => new \Twig_Filter_Method($this, 'myFunction'),
        );
    }

    public function myFunction($text)
    {
       return $this->environment->render($someTemplate,$someArguments);
    }
}

Documentation: Creating an extension.

Sign up to request clarification or add additional context in comments.

2 Comments

Yes, this works when I'm using the service in a twig template for sure. But then how do I call it as a service as per : $myService = $this->container->get('Acme.twig.my_extension'); $text = $myService->myFunction($someValue); ... I need to pass the twig environment somehow
Twig environment calls the method automatically in loadTemplate(). I guess you could force it by calling $twig->initRuntime() which will initialise all the extensions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.