diff --git a/Command/DebugCommand.php b/Command/DebugCommand.php index 21ede17a..0eaacfbf 100644 --- a/Command/DebugCommand.php +++ b/Command/DebugCommand.php @@ -550,7 +550,7 @@ private function getRelativePath(string $path): string private function isAbsolutePath(string $file): bool { - return strspn($file, '/\\', 0, 1) || (\strlen($file) > 3 && ctype_alpha($file[0]) && ':' === $file[1] && strspn($file, '/\\', 2, 1)) || null !== parse_url($file, \PHP_URL_SCHEME); + return strspn($file, '/\\', 0, 1) || (\strlen($file) > 3 && ctype_alpha($file[0]) && ':' === $file[1] && strspn($file, '/\\', 2, 1)) || parse_url($file, \PHP_URL_SCHEME); } /** diff --git a/Node/DumpNode.php b/Node/DumpNode.php index f23313c7..2c474f15 100644 --- a/Node/DumpNode.php +++ b/Node/DumpNode.php @@ -14,6 +14,7 @@ use Twig\Attribute\FirstClassTwigCallableReady; use Twig\Attribute\YieldReady; use Twig\Compiler; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\Node; /** @@ -23,7 +24,7 @@ final class DumpNode extends Node { public function __construct( - private string $varPrefix, + private LocalVariable|string $varPrefix, ?Node $values, int $lineno, ?string $tag = null, @@ -44,6 +45,12 @@ public function __construct( public function compile(Compiler $compiler): void { + if ($this->varPrefix instanceof LocalVariable) { + $varPrefix = $this->varPrefix->getAttribute('name'); + } else { + $varPrefix = $this->varPrefix; + } + $compiler ->write("if (\$this->env->isDebug()) {\n") ->indent(); @@ -51,18 +58,18 @@ public function compile(Compiler $compiler): void if (!$this->hasNode('values')) { // remove embedded templates (macros) from the context $compiler - ->write(sprintf('$%svars = [];'."\n", $this->varPrefix)) - ->write(sprintf('foreach ($context as $%1$skey => $%1$sval) {'."\n", $this->varPrefix)) + ->write(sprintf('$%svars = [];'."\n", $varPrefix)) + ->write(sprintf('foreach ($context as $%1$skey => $%1$sval) {'."\n", $varPrefix)) ->indent() - ->write(sprintf('if (!$%sval instanceof \Twig\Template) {'."\n", $this->varPrefix)) + ->write(sprintf('if (!$%sval instanceof \Twig\Template) {'."\n", $varPrefix)) ->indent() - ->write(sprintf('$%1$svars[$%1$skey] = $%1$sval;'."\n", $this->varPrefix)) + ->write(sprintf('$%1$svars[$%1$skey] = $%1$sval;'."\n", $varPrefix)) ->outdent() ->write("}\n") ->outdent() ->write("}\n") ->addDebugInfo($this) - ->write(sprintf('\Symfony\Component\VarDumper\VarDumper::dump($%svars);'."\n", $this->varPrefix)); + ->write(sprintf('\Symfony\Component\VarDumper\VarDumper::dump($%svars);'."\n", $varPrefix)); } elseif (($values = $this->getNode('values')) && 1 === $values->count()) { $compiler ->addDebugInfo($this) diff --git a/Node/StopwatchNode.php b/Node/StopwatchNode.php index 239d1ca6..e8ac13d6 100644 --- a/Node/StopwatchNode.php +++ b/Node/StopwatchNode.php @@ -15,6 +15,7 @@ use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Expression\AssignNameExpression; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\Node; /** @@ -25,8 +26,15 @@ #[YieldReady] final class StopwatchNode extends Node { - public function __construct(Node $name, Node $body, AssignNameExpression $var, int $lineno = 0, ?string $tag = null) + /** + * @param AssignNameExpression|LocalVariable $var + */ + public function __construct(Node $name, Node $body, $var, int $lineno = 0, ?string $tag = null) { + if (!$var instanceof AssignNameExpression && !$var instanceof LocalVariable) { + throw new \TypeError(sprintf('Expected an instance of "%s" or "%s", but got "%s".', AssignNameExpression::class, LocalVariable::class, get_debug_type($var))); + } + if (class_exists(FirstClassTwigCallableReady::class)) { parent::__construct(['body' => $body, 'name' => $name, 'var' => $var], [], $lineno); } else { diff --git a/Node/TransNode.php b/Node/TransNode.php index 42126399..a61ee4db 100644 --- a/Node/TransNode.php +++ b/Node/TransNode.php @@ -18,6 +18,7 @@ use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Node\TextNode; @@ -124,7 +125,7 @@ private function compileString(Node $body, ArrayExpression $vars, bool $ignoreSt if ('count' === $var && $this->hasNode('count')) { $vars->addElement($this->getNode('count'), $key); } else { - $varExpr = new NameExpression($var, $body->getTemplateLine()); + $varExpr = class_exists(ContextVariable::class) ? new ContextVariable($var, $body->getTemplateLine()) : new NameExpression($var, $body->getTemplateLine()); $varExpr->setAttribute('ignore_strict_check', $ignoreStrictCheck); $vars->addElement($varExpr, $key); } diff --git a/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/NodeVisitor/TranslationDefaultDomainNodeVisitor.php index 9066de82..1d5ff9d8 100644 --- a/NodeVisitor/TranslationDefaultDomainNodeVisitor.php +++ b/NodeVisitor/TranslationDefaultDomainNodeVisitor.php @@ -20,6 +20,8 @@ use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FilterExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\AssignContextVariable; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\ModuleNode; use Twig\Node\Node; use Twig\Node\Nodes; @@ -51,8 +53,8 @@ public function enterNode(Node $node, Environment $env): Node return $node; } else { $var = $this->getVarName(); - $name = new AssignNameExpression($var, $node->getTemplateLine()); - $this->scope->set('domain', new NameExpression($var, $node->getTemplateLine())); + $name = class_exists(AssignContextVariable::class) ? new AssignContextVariable($var, $node->getTemplateLine()) : new AssignNameExpression($var, $node->getTemplateLine()); + $this->scope->set('domain', class_exists(ContextVariable::class) ? new ContextVariable($var, $node->getTemplateLine()) : new NameExpression($var, $node->getTemplateLine())); if (class_exists(Nodes::class)) { return new SetNode(false, new Nodes([$name]), new Nodes([$node->getNode('expr')]), $node->getTemplateLine()); diff --git a/Tests/Node/DumpNodeTest.php b/Tests/Node/DumpNodeTest.php index a19ba041..6d584c89 100644 --- a/Tests/Node/DumpNodeTest.php +++ b/Tests/Node/DumpNodeTest.php @@ -17,6 +17,7 @@ use Twig\Environment; use Twig\Loader\LoaderInterface; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Node\Nodes; @@ -74,7 +75,7 @@ public function testOneVar() { if (class_exists(Nodes::class)) { $vars = new Nodes([ - new NameExpression('foo', 7), + new ContextVariable('foo', 7), ]); } else { $vars = new Node([ @@ -104,8 +105,8 @@ public function testMultiVars() { if (class_exists(Nodes::class)) { $vars = new Nodes([ - new NameExpression('foo', 7), - new NameExpression('bar', 7), + new ContextVariable('foo', 7), + new ContextVariable('bar', 7), ]); } else { $vars = new Node([ diff --git a/Tests/Node/FormThemeTest.php b/Tests/Node/FormThemeTest.php index 3bbbe2d9..e0bb3d55 100644 --- a/Tests/Node/FormThemeTest.php +++ b/Tests/Node/FormThemeTest.php @@ -22,6 +22,7 @@ use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Node\Nodes; @@ -31,7 +32,7 @@ class FormThemeTest extends TestCase public function testConstructor() { - $form = new NameExpression('form', 0); + $form = class_exists(ContextVariable::class) ? new ContextVariable('form', 0) : new NameExpression('form', 0); if (class_exists(Nodes::class)) { $resources = new Nodes([ new ConstantExpression('tpl1', 0), @@ -53,7 +54,7 @@ public function testConstructor() public function testCompile() { - $form = new NameExpression('form', 0); + $form = class_exists(ContextVariable::class) ? new ContextVariable('form', 0) : new NameExpression('form', 0); $resources = new ArrayExpression([ new ConstantExpression(1, 0), new ConstantExpression('tpl1', 0), diff --git a/Tests/Node/SearchAndRenderBlockNodeTest.php b/Tests/Node/SearchAndRenderBlockNodeTest.php index 582eb6d0..5c2bacf1 100644 --- a/Tests/Node/SearchAndRenderBlockNodeTest.php +++ b/Tests/Node/SearchAndRenderBlockNodeTest.php @@ -22,6 +22,7 @@ use Twig\Node\Expression\ConditionalExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Node\Nodes; use Twig\TwigFunction; @@ -32,7 +33,7 @@ public function testCompileWidget() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), ]); } else { $arguments = new Node([ @@ -61,7 +62,7 @@ public function testCompileWidgetWithVariables() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ArrayExpression([ new ConstantExpression('foo', 0), new ConstantExpression('bar', 0), @@ -98,7 +99,7 @@ public function testCompileLabelWithLabel() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ConstantExpression('my label', 0), ]); } else { @@ -129,7 +130,7 @@ public function testCompileLabelWithNullLabel() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ConstantExpression(null, 0), ]); } else { @@ -162,7 +163,7 @@ public function testCompileLabelWithEmptyStringLabel() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ConstantExpression('', 0), ]); } else { @@ -195,7 +196,7 @@ public function testCompileLabelWithDefaultLabel() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), ]); } else { $arguments = new Node([ @@ -224,7 +225,7 @@ public function testCompileLabelWithAttributes() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ConstantExpression(null, 0), new ArrayExpression([ new ConstantExpression('foo', 0), @@ -266,7 +267,7 @@ public function testCompileLabelWithLabelAndAttributes() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ConstantExpression('value in argument', 0), new ArrayExpression([ new ConstantExpression('foo', 0), @@ -309,7 +310,7 @@ public function testCompileLabelWithLabelThatEvaluatesToNull() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ConditionalExpression( // if new ConstantExpression(true, 0), @@ -360,7 +361,7 @@ public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes() { if (class_exists(Nodes::class)) { $arguments = new Nodes([ - new NameExpression('form', 0), + new ContextVariable('form', 0), new ConditionalExpression( // if new ConstantExpression(true, 0), diff --git a/Tests/Node/TransNodeTest.php b/Tests/Node/TransNodeTest.php index d1f1114f..c5542ea0 100644 --- a/Tests/Node/TransNodeTest.php +++ b/Tests/Node/TransNodeTest.php @@ -17,6 +17,7 @@ use Twig\Environment; use Twig\Loader\LoaderInterface; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\TextNode; /** @@ -27,7 +28,7 @@ class TransNodeTest extends TestCase public function testCompileStrict() { $body = new TextNode('trans %var%', 0); - $vars = new NameExpression('foo', 0); + $vars = class_exists(ContextVariable::class) ? new ContextVariable('foo', 0) : new NameExpression('foo', 0); $node = new TransNode($body, null, null, $vars); $env = new Environment($this->createMock(LoaderInterface::class), ['strict_variables' => true]); diff --git a/Tests/NodeVisitor/TranslationNodeVisitorTest.php b/Tests/NodeVisitor/TranslationNodeVisitorTest.php index 96134b6e..6dbd0d27 100644 --- a/Tests/NodeVisitor/TranslationNodeVisitorTest.php +++ b/Tests/NodeVisitor/TranslationNodeVisitorTest.php @@ -20,6 +20,7 @@ use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FilterExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Node\Nodes; use Twig\TwigFilter; @@ -44,7 +45,7 @@ public function testMessageExtractionWithInvalidDomainNode() if (class_exists(Nodes::class)) { $n = new Nodes([ new ArrayExpression([], 0), - new NameExpression('variable', 0), + new ContextVariable('variable', 0), ]); } else { $n = new Node([ diff --git a/Tests/TokenParser/FormThemeTokenParserTest.php b/Tests/TokenParser/FormThemeTokenParserTest.php index c9c0ce80..02b6597c 100644 --- a/Tests/TokenParser/FormThemeTokenParserTest.php +++ b/Tests/TokenParser/FormThemeTokenParserTest.php @@ -20,6 +20,7 @@ use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Parser; use Twig\Source; @@ -51,7 +52,7 @@ public static function getTestsForFormTheme() [ '{% form_theme form "tpl1" %}', new FormThemeNode( - new NameExpression('form', 1), + class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new NameExpression('form', 1), new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression('tpl1', 1), @@ -63,7 +64,7 @@ public static function getTestsForFormTheme() [ '{% form_theme form "tpl1" "tpl2" %}', new FormThemeNode( - new NameExpression('form', 1), + class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new NameExpression('form', 1), new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression('tpl1', 1), @@ -77,7 +78,7 @@ public static function getTestsForFormTheme() [ '{% form_theme form with "tpl1" %}', new FormThemeNode( - new NameExpression('form', 1), + class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new NameExpression('form', 1), new ConstantExpression('tpl1', 1), 1, 'form_theme' @@ -86,7 +87,7 @@ public static function getTestsForFormTheme() [ '{% form_theme form with ["tpl1"] %}', new FormThemeNode( - new NameExpression('form', 1), + class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new NameExpression('form', 1), new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression('tpl1', 1), @@ -98,7 +99,7 @@ public static function getTestsForFormTheme() [ '{% form_theme form with ["tpl1", "tpl2"] %}', new FormThemeNode( - new NameExpression('form', 1), + class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new NameExpression('form', 1), new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression('tpl1', 1), @@ -112,7 +113,7 @@ public static function getTestsForFormTheme() [ '{% form_theme form with ["tpl1", "tpl2"] only %}', new FormThemeNode( - new NameExpression('form', 1), + class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new NameExpression('form', 1), new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression('tpl1', 1), diff --git a/TokenParser/DumpTokenParser.php b/TokenParser/DumpTokenParser.php index d4996dbe..e671f9ba 100644 --- a/TokenParser/DumpTokenParser.php +++ b/TokenParser/DumpTokenParser.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Twig\TokenParser; use Symfony\Bridge\Twig\Node\DumpNode; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\Node; use Twig\Token; use Twig\TokenParser\AbstractTokenParser; @@ -37,7 +38,7 @@ public function parse(Token $token): Node } $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); - return new DumpNode($this->parser->getVarName(), $values, $token->getLine(), $this->getTag()); + return new DumpNode(class_exists(LocalVariable::class) ? new LocalVariable(null, $token->getLine()) : $this->parser->getVarName(), $values, $token->getLine(), $this->getTag()); } public function getTag(): string diff --git a/TokenParser/StopwatchTokenParser.php b/TokenParser/StopwatchTokenParser.php index 810e7c27..ac6baa6d 100644 --- a/TokenParser/StopwatchTokenParser.php +++ b/TokenParser/StopwatchTokenParser.php @@ -13,6 +13,7 @@ use Symfony\Bridge\Twig\Node\StopwatchNode; use Twig\Node\Expression\AssignNameExpression; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\Node; use Twig\Token; use Twig\TokenParser\AbstractTokenParser; @@ -44,7 +45,7 @@ public function parse(Token $token): Node $stream->expect(Token::BLOCK_END_TYPE); if ($this->stopwatchIsAvailable) { - return new StopwatchNode($name, $body, new AssignNameExpression($this->parser->getVarName(), $token->getLine()), $lineno, $this->getTag()); + return new StopwatchNode($name, $body, class_exists(LocalVariable::class) ? new LocalVariable(null, $token->getLine()) : new AssignNameExpression($this->parser->getVarName(), $token->getLine()), $lineno, $this->getTag()); } return $body;