Reputation: 5986
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
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
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
Reputation: 16602
I think there are two solutions for this, both should use the Twig_Function_Method
class.
The first solution gilden
already posted, is to encapsulate the logic into a service and make a wrapper for the Twig Extension.
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
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