After upgrading my site to Drupal 8.3.0, my existing twig extensions which were previously working fine don't work anymore, and their presence actually causes the site to not load. The following error is in my nginx logs:
2017/04/12 16:40:32 [error] 1428#0: *10 FastCGI sent in stderr: "PHP message: Recoverable fatal error: Argument 2 passed to Drupal\Core\Template\TwigExtension::__construct() must implement interface Drupal\Core\Routing\UrlGeneratorInterface, none given, called in /var/www/core/lib/Drupal/Component/DependencyInjection/Container.php on line 268 and defined in /var/www/core/lib/Drupal/Core/Template/TwigExtension.php on line 68 #0 /var/www/core/includes/bootstrap.inc(552): _drupal_error_handler_real(4096, 'Argument 2 pass...', '/var/www/core/l...', 68, Array)
#1 /var/www/core/lib/Drupal/Core/Template/TwigExtension.php(68): _drupal_error_handler(4096, 'Argument 2 pass...', '/var/www/core/l...', 68, Array)
#2 /var/www/core/lib/Drupal/Component/DependencyInjection/Container.php(268): Drupal\Core\Template\TwigExtension->__construct(Object(Drupal\Core\Render\Renderer))
#3 /var/www/core/lib/Drupal/Component/DependencyInjection/Container.php(177): Drupal\Component\DependencyInjection\Container->createService(Array, 'my_module.twig.g...')
#4 /var/www/core/lib/Drupal/Component/Depen" while reading response header from upstream, client: my-ip-address, server: my-domain, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php5.6-fpm.sock:", host: "my-domain"
Here is an example extension which worked on 8.2.x. This issue has been happening for all twig extensions, not just this simple and probably unnecessary one:
/modes/custom/my_module/src/TwigExtension/GetQueryParam.php:
namespace Drupal\my_module\TwigExtension;
use Drupal\Core\Template\TwigExtension;
class getQueryParam extends TwigExtension {
public function getFunctions() {
return array(
'get_query_param' => new \Twig_Function_Function(['Drupal\my_module\TwigExtension\GetQueryParam', 'getQueryParam']),
);
}
public function getName() {
return 'my_module.get_query_param';
}
public static function getQueryParam($param) {
return (isset($_GET[$param]) ? $_GET[$param] : NULL);
}
}
/modules/custom/my_module/my_module.services.yml:
services:
my_module.twig.get_query_param:
arguments: ['@renderer']
class: Drupal\my_module\TwigExtension\GetQueryParam
tags:
- { name: twig.extension }
I'll be investigating to see if I can find a solution, since I can't update to 8.3.0 currently. No obvious fix stood out to me, and there's nothing in the 8.3 changelog discussing a change to how TwigExtensions works; I know Twig itself was updated, but that ticket (#2804365) doesn't indicate any change to how extensions would work with regards to this URlGeneratorInterface class which the error message is concerned about.
If there was some change to how TwigExtensions should be created that breaks backwards compatibility, it seems like either a bug or like something that should be noted in the change notes for 8.3.
Comments
Comment #1
Anonymous (not verified) commentedJKerschner created an issue. See original summary.
Comment #2
Anonymous (not verified) commentedComment #3
cilefen commentedDrupal\Core\Template\TwigExtension is itself an implementation. If you extend Drupal\Core\Template\TwigExtension rather than \Twig_Extension, you will have to feed its constructor in the service definition. It seems in this case you should be extending \Twig_Extension.
I hope this helps!
Comment #4
Anonymous (not verified) commentedSo there seem to be two potential fixes. One is to, in the services.yml file, change
to
The other way of fixing it is to change from extending Drupal\Core\Template\TwigExtension to extending \Twig_Extension (and leaving the services file unchanged), which I suspect is the better way of changing it since that is how the TestExtension in core has been changed.
Regardless, it seems like this change should be noted somewhere in the change notes for Drupal 8.3.0... it breaks backwards compatibility since the version I initially posted was working fine prior to 8.3.0, and in fact my code was based off of the TestExtension, indicating to me that it was not only "working" but also the recommended way of creating a Twig extension at the time.
Comment #5
Anonymous (not verified) commentedAh, thank you cilefen, that's the same result I came to. Just surprising to see a change like this not documented anywhere in the 8.3.0 changelog given that it takes down the entire site until it is fixed, and the error message isn't particularly illuminating about how to update the code.
Comment #6
cilefen commentedFrom https://www.drupal.org/core/d8-bc-policy:
Comment #7
Anonymous (not verified) commentedHuh. Just surprised to see something which was previously the recommended way to do it in one of core's tests is considered "internal" to the extent that no note even needs to be made of it for backwards compatibility. I'm sure this will be tripping up other people (at least one person encountered the same issue and reported it on StackOverflow). I guess that closes this ticket then if official policy is that this isn't an issue, though I'd say that that particular part of the policy is perhaps flawed since the "right" way to do something in 8.2.x (going by the example usage in TestExtension) not working at all in 8.3.0 seems like a noteworthy backwards compatibility change... a change worth making in this case, but also, I'd feel, one worth noting.
Thank you for your help!
Comment #8
cilefen commentedI retitled it for Google.
It is the same answer from other maintainers on SE. I agree that tests are not always the best examples. TestExtension should not have extended TwigExtension if not overriding anything.
Comment #9
Anonymous (not verified) commentedSounds good, thanks.
As a note for anyone else coming here later: If you switch to using /Twig_Extension instead of TwigExtension, it also appears that you can remove the following from the service definition entirely:
Comment #10
cilefen commented#9 depends on whether your class has a constructor and needs other services.
Comment #11
joelpittetJust to help with the discussion here, we are trying to remove that to make 2.0.0 twig transition easier. Have a look here #2600154: Update our Twig code to be ready for Twig 2.x