15

I have a slugify method in an Twig Extension which i would like to use in some cases in a controller, f.e with redirects.
Is there an easy way for this?
How could i access functions from Twig Extensions in the controller?

Or do i have to make the slugify method somewere as a helper in order to use it in the code and in twig?

ivoba
  • 5,283
  • 4
  • 40
  • 50

3 Answers3

8

Access function / logic from twig and a controller

I think there are two solutions for this, both should use the Twig_Function_Method class.

1

The first solution gilden already posted, is to encapsulate the logic into a service and make a wrapper for the Twig Extension.

2

Another solution is to use only the Twig Extension. The Twig Extensino is already a service, you have to define it as service with the special <tag name="twig.extension" />. But it's also a service, which instance you can grab by the service container. And it's also possible to inject other services:

So you have your Twig Extension / Service:

class MyTwigExtension extends \Twig_Extension
{
    private $anotherService;

    public function __construct(SecurityService $anotherService= null)
    {
        $this->anotherService = $anotherService;
    }

    public function foo($param)
    {
       // do something
       $this->anotherService->bar($param);
    }


    public function getFunctions()
    {
        // function names in twig => function name in this calss
        return array(
            'foo' => new \Twig_Function_Method($this, 'foo'),
        );
    }

    /**
     * Returns the name of the extension.
     *
     * @return string The extension name
     */
    public function getName()
    {
        return 'my_extension';
    }
}

The services.xml looks like this

<service id="acme.my_extension" class="Acme\CoreBundle\Twig\Extension\MyTwigExtension">
        <tag name="twig.extension" />
        <argument type="service" id="another.service"></argument>
</service>

To acccess to the service from your controller you only have to use this:
$this->container->get('acme.my_extension')

Notice The only difference to a normal service is, that the twig extension is not lazy loaded (http://symfony.com/doc/current/cookbook/templating/twig_extension.html#register-an-extension-as-a-service)

stefita
  • 1,715
  • 2
  • 20
  • 34
timaschew
  • 15,034
  • 4
  • 56
  • 73
  • Very good point about twig extension being a service already. Saved a lot of time and effort. Thanks! – Wiseman Jul 19 '16 at 07:40
  • 1
    Remember that the service must be declared as public. If someone follows the example from the cookbook, then must to change that. http://symfony.com/doc/current/cookbook/templating/twig_extension.html – glerendegui Jul 27 '16 at 16:35
7

I would advise creating a general service and injecting it to the Twig extension. The extension would act just as a wrapper to the service.

namespace Acme\Bundle\DemoBundle\...;

class MyService
{
    public function myFunc($foo, $bar)
    {
        // some code...
    }

    // additional methods...
}

EDIT - as mentioned by Squazic, the first argument must implement Twig_ExtensionInterface. An inelegant solution would be to add methods to MyTwigExtension, that in turn call out respective methods in the service.

namespace Acme\Bundle\DemoBundle\Twig\Extension;

class MyTwigExtension extends \Twig_Extension
{
    protected $service;

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

    public function getFunctions()
    {
        return array(
            'myTwigFunction' => new \Twig_Function_Method($this, 'myFunc'),
            'mySecondFunc'   => new \Twig_Function_Method($this, 'mySecondFunc'),
        );
    }

    public function myFunc($foo, $bar)
    {
        return $this->service->myFunc($foo, $bar);
    }

    // etc...

}
kgilden
  • 10,116
  • 3
  • 44
  • 46
  • Alright, i see, so i should make something like a StringHelper Service and inject it where it need it. Thank you – ivoba Jul 11 '12 at 12:35
  • I tried this but got an error because the first argument to `Twig_Function_Method` has to implement `Twig_ExtensionInterface` – Squazic Sep 27 '12 at 20:36
  • @Squazic You are indeed correct. I wrote a work-around for this. – kgilden Sep 27 '12 at 21:02
  • @gilden You mention that this is not elegant. Do you know of a more elegant way of approaching the problem? – Squazic Sep 27 '12 at 22:31
  • @Squazic I'm afraid not. You could, however, make this a tad more DRY by having [`MyTwigExtension::__call`](http://www.php.net/manual/en/language.oop5.overloading.php#object.call) forward all method calls to the service object. – kgilden Sep 30 '12 at 22:54
1

Or another way is to get it via twig... (this is on Symfony 2.7)

$twigExt = $this->container->get('twig')->getExtension(TwigExtensionClassName::class);

So if your Twig extension class is called 'MyFabulousTwigExt', then you'd call

$twigExt = $this->container->get('twig')->getExtension(MyFabulousTwigExt::class);

This worked for me when the above didn't (our extension wasn't also a service)

Steve Childs
  • 1,649
  • 2
  • 16
  • 25