diff --git a/src/TwigHooks/src/Twig/Node/HookNode.php b/src/TwigHooks/src/Twig/Node/HookNode.php index 9f8b50ffd..7afe1029d 100644 --- a/src/TwigHooks/src/Twig/Node/HookNode.php +++ b/src/TwigHooks/src/Twig/Node/HookNode.php @@ -14,10 +14,12 @@ namespace Sylius\TwigHooks\Twig\Node; use Sylius\TwigHooks\Twig\Runtime\HooksRuntime; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Node; +#[YieldReady] final class HookNode extends Node { public function __construct( @@ -25,19 +27,38 @@ public function __construct( ?Node $context, bool $only, int $lineno, - ?string $tag = null, ) { - parent::__construct( - [ - 'name' => $name, - 'hook_level_context' => $context ?? new ArrayExpression([], $lineno), - ], - [ - 'only' => $only, - ], - $lineno, - $tag, - ); + if (\func_num_args() > 4) { + trigger_deprecation('sylius/twig-hooks', '0.10.0', \sprintf('The "tag" constructor argument of the "%s" class is deprecated and ignored (check which TokenParser class set it to "%s"), the tag is now automatically set by the Parser when needed.', static::class, func_get_arg(4) ?: 'null')); + } + + if (class_exists(\Twig\Node\Expression\FunctionNode\EnumCasesFunction::class)) { + parent::__construct( + [ + 'name' => $name, + 'hook_level_context' => $context ?? new ArrayExpression([], $lineno), + ], + [ + 'only' => $only, + ], + $lineno, + ); + } else { + // Remove when twig < 3.12 support is dropped + $tag = func_get_arg(4); + + parent::__construct( + [ + 'name' => $name, + 'hook_level_context' => $context ?? new ArrayExpression([], $lineno), + ], + [ + 'only' => $only, + ], + $lineno, + $tag, + ); + } } public function compile(Compiler $compiler): void @@ -49,7 +70,7 @@ public function compile(Compiler $compiler): void HooksRuntime::class, ))->raw("\n"); - $compiler->raw('echo $hooksRuntime->renderHook('); + $compiler->raw(sprintf('%s $hooksRuntime->renderHook(', class_exists(YieldReady::class) ? 'yield' : 'echo')); $compiler->subcompile($this->getNode('name')); $compiler->raw(', '); $compiler->subcompile($this->getNode('hook_level_context')); diff --git a/src/TwigHooks/src/Twig/TokenParser/HookTokenParser.php b/src/TwigHooks/src/Twig/TokenParser/HookTokenParser.php index 330811c15..e549221b6 100644 --- a/src/TwigHooks/src/Twig/TokenParser/HookTokenParser.php +++ b/src/TwigHooks/src/Twig/TokenParser/HookTokenParser.php @@ -15,6 +15,7 @@ use Sylius\TwigHooks\Twig\Node\HookNode; use Twig\Node\Node; +use Twig\Node\Nodes; use Twig\Token; use Twig\TokenParser\AbstractTokenParser; @@ -26,11 +27,21 @@ public function parse(Token $token): Node { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - $hooksNames = $this->parser->getExpressionParser()->parseExpression(); + if (method_exists($this->parser, 'parseExpression')) { + $hooksNames = $this->parser->parseExpression(); + } else { + // Remove when Twig 3.21 support is dropped + $hooksNames = $this->parser->getExpressionParser()->parseExpression(); + } $hookContext = null; if ($stream->nextIf(Token::NAME_TYPE, 'with')) { - $hookContext = $this->parser->getExpressionParser()->parseMultitargetExpression(); + if (method_exists($this->parser, 'parseExpression')) { + $hookContext = $this->parseMultitargetExpression(); + } else { + // Remove when Twig 3.21 support is dropped + $hookContext = $this->parser->getExpressionParser()->parseMultitargetExpression(); + } } $only = false; @@ -40,6 +51,11 @@ public function parse(Token $token): Node $stream->expect(Token::BLOCK_END_TYPE); + if (class_exists(\Twig\Node\Expression\FunctionNode\EnumCasesFunction::class)) { + return new HookNode($hooksNames, $hookContext, $only, $lineno); + } + + // Remove when twig < 3.12 support is dropped return new HookNode($hooksNames, $hookContext, $only, $lineno, $this->getTag()); } @@ -47,4 +63,17 @@ public function getTag(): string { return self::TAG; } + + private function parseMultitargetExpression(): Nodes + { + $targets = []; + while (true) { + $targets[] = $this->parser->parseExpression(); + if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ',')) { + break; + } + } + + return new Nodes($targets); + } }