Be careful with global variables in Symfony 2 Twig extensions
I stumbled across a confusing error message while developing some new functionality in one of my Symfony 2 based applications.
I was using some Behat scenarios to guide me through a payment listener that emails a customer when their payment has been confirmed. Everything was working fine until I tried to introduce a Twig template as the body of an email.
[Symfony\Component\DependencyInjection\Exception\InactiveScopeException] You cannot create a service ("request") of an inactive scope ("request").
Initially I was stumped, the error message did not point me directly to any code I was working with, nor anything I had recently looked at.
After a lot of head scratching I remembered a Twig extension that I had written over a year ago. It helps to conditionally execute javascript based on the users current location within the application (inspired by Paul Irish's blog post).
// ../Twig/Extension/MyExtension.php
public function getRouteInfo()
{
$request = $this->container->get('request');
// ... process the route information
return $routeInfo;
}
In order to make $routeInfo
available to all my templates, I had decided
to make it to global.
// ../Twig/Extension/MyExtension.php
public function getGlobals()
{
return ['route' => $this->getRouteInfo()];
}
The problem with this is that I have given my Twig environment a hard dependency
on the Request
object. Every time I try and use Twig, it will make that getGlobals
call, which in turn will be trying to access the Request
object.
This is why, in the CLI context where there is no Request
object I was seeing
the inactive scope exception. While I would not necessarily take the above approach
again, the fix is quite easy — the Symfony 2 container provides a method
for checking if a scope is active or not, which means I can rewrite my
getRouteInfo
method:
// ../Twig/Extension/MyExtension.php
public function getRouteInfo()
{
if (!$this->container->isScopeActive('request')) {
return null;
}
$request = $this->container->get('request');
// ...
return $routeInfo;
}
I generally try and shy away from making variables global (in any context) and
this example reinforces my wariness of using getGlobals
in Twig extensions.
Share on twitter