ivoba
ivoba

Reputation: 5986

Use Twig Extension in controller

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?

Upvotes: 15

Views: 16572

Answers (4)

Jonathan
Jonathan

Reputation: 15432

I've found this to be the best way of calling the extension directly (tested in Symfony 4.4):

use Twig\Environment;

private Environment $twig;

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

public function foo()
{
    $extensionOutput = $this->twig
        ->getExtension(YourExtension::class)
        ->yourExtensionFunction(
            $this->twig,
            $value
        );
    ...
}

Useful if you don't want to (or can't) break the logic out of the Twig extension.

Upvotes: 0

Steve Childs
Steve Childs

Reputation: 1872

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)

Upvotes: 2

timaschew
timaschew

Reputation: 16602

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)

Upvotes: 8

kgilden
kgilden

Reputation: 10356

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...

}

Upvotes: 8

Related Questions