mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-30 20:16:45 +00:00
feature #4874 Normalize destructuring assignment targets (fabpot)
This PR was merged into the 3.x branch.
Discussion
----------
Normalize destructuring assignment targets
Commits
-------
6ce5beb7c2 Normalize destructuring assignment targets
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# 3.29.0 (2026-XX-XX)
|
||||
|
||||
* Normalize destructuring variable AST nodes as assignment targets
|
||||
* Fix `IntlExtension` ignoring explicit date/time formats and the `format_date`/`format_time` filters when a date formatter prototype is configured
|
||||
* Add a `format_list` filter to `IntlExtension` to format a list of strings using PHP 8.5's `IntlListFormatter`
|
||||
* Fix array access with a `Stringable` key coercing the key to string for `ArrayAccess` objects that use object keys (such as `SplObjectStorage`)
|
||||
|
||||
@@ -19,6 +19,7 @@ use Twig\Node\Expression\Binary\AbstractBinary;
|
||||
use Twig\Node\Expression\Binary\ObjectDestructuringSetBinary;
|
||||
use Twig\Node\Expression\Binary\SequenceDestructuringSetBinary;
|
||||
use Twig\Node\Expression\Binary\SetBinary;
|
||||
use Twig\Node\Expression\Variable\AssignContextVariable;
|
||||
use Twig\Node\Expression\Variable\ContextVariable;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
@@ -49,6 +50,12 @@ class AssignmentExpressionParser extends BinaryOperatorExpressionParser
|
||||
};
|
||||
|
||||
if ($left instanceof ArrayExpression) {
|
||||
foreach ($left->getKeyValuePairs() as $i => $pair) {
|
||||
if ($pair['value'] instanceof ContextVariable && !$pair['value'] instanceof AssignContextVariable) {
|
||||
$left->setNode(2 * $i + 1, new AssignContextVariable($pair['value']->getAttribute('name'), $pair['value']->getTemplateLine()));
|
||||
}
|
||||
}
|
||||
|
||||
if ($left->isSequence()) {
|
||||
return new SequenceDestructuringSetBinary($left, $right, $token->getLine());
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use Twig\Error\SyntaxError;
|
||||
use Twig\Extension\SandboxExtension;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\Variable\ContextVariable;
|
||||
use Twig\Node\Expression\Variable\AssignContextVariable;
|
||||
use Twig\Node\Node;
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ class ObjectDestructuringSetBinary extends AbstractBinary
|
||||
throw new \LogicException('Left side must be ArrayExpression for object/mapping destructuring.');
|
||||
}
|
||||
foreach ($left->getKeyValuePairs() as $pair) {
|
||||
if (!$pair['value'] instanceof ContextVariable) {
|
||||
if (!$pair['value'] instanceof AssignContextVariable) {
|
||||
throw new SyntaxError(\sprintf('Cannot assign to "%s", only variables can be assigned in object/mapping destructuring.', $pair['value']::class), $lineno);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use Twig\Error\SyntaxError;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\EmptyExpression;
|
||||
use Twig\Node\Expression\Variable\ContextVariable;
|
||||
use Twig\Node\Expression\Variable\AssignContextVariable;
|
||||
use Twig\Node\Node;
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ class SequenceDestructuringSetBinary extends AbstractBinary
|
||||
foreach ($left->getKeyValuePairs() as $pair) {
|
||||
if ($pair['value'] instanceof EmptyExpression) {
|
||||
$this->variables[] = null;
|
||||
} elseif ($pair['value'] instanceof ContextVariable) {
|
||||
} elseif ($pair['value'] instanceof AssignContextVariable) {
|
||||
$this->variables[] = $pair['value']->getAttribute('name');
|
||||
} else {
|
||||
throw new SyntaxError(\sprintf('Cannot assign to "%s", only variables can be assigned in sequence destructuring.', $pair['value']::class), $lineno);
|
||||
|
||||
@@ -37,12 +37,16 @@ use Twig\Extension\AbstractExtension;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\Binary\ConcatBinary;
|
||||
use Twig\Node\Expression\Binary\ObjectDestructuringSetBinary;
|
||||
use Twig\Node\Expression\Binary\SequenceDestructuringSetBinary;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\EmptyExpression;
|
||||
use Twig\Node\Expression\FilterExpression;
|
||||
use Twig\Node\Expression\FunctionExpression;
|
||||
use Twig\Node\Expression\TestExpression;
|
||||
use Twig\Node\Expression\Unary\AbstractUnary;
|
||||
use Twig\Node\Expression\Unary\SpreadUnary;
|
||||
use Twig\Node\Expression\Variable\AssignContextVariable;
|
||||
use Twig\Node\Expression\Variable\ContextVariable;
|
||||
use Twig\Node\Node;
|
||||
use Twig\Parser;
|
||||
@@ -249,6 +253,35 @@ class ExpressionParserTest extends TestCase
|
||||
$env->compileSource(new Source('{{ [1,,2] }}', 'index'));
|
||||
}
|
||||
|
||||
public function testSequenceDestructuringUsesAssignmentTargets(): void
|
||||
{
|
||||
$env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]);
|
||||
$parser = new Parser($env);
|
||||
$node = $parser->parse($env->tokenize(new Source('{{ ([first, , third] = values) }}', 'index')))->getNode('body')->getNode('0')->getNode('expr');
|
||||
|
||||
$this->assertInstanceOf(SequenceDestructuringSetBinary::class, $node);
|
||||
$pairs = $node->getNode('left')->getKeyValuePairs();
|
||||
$this->assertSame(AssignContextVariable::class, $pairs[0]['value']::class);
|
||||
$this->assertSame('first', $pairs[0]['value']->getAttribute('name'));
|
||||
$this->assertSame(EmptyExpression::class, $pairs[1]['value']::class);
|
||||
$this->assertSame(AssignContextVariable::class, $pairs[2]['value']::class);
|
||||
$this->assertSame('third', $pairs[2]['value']->getAttribute('name'));
|
||||
}
|
||||
|
||||
public function testObjectDestructuringUsesAssignmentTargets(): void
|
||||
{
|
||||
$env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]);
|
||||
$parser = new Parser($env);
|
||||
$node = $parser->parse($env->tokenize(new Source('{{ ({name: user_name} = user) }}', 'index')))->getNode('body')->getNode('0')->getNode('expr');
|
||||
|
||||
$this->assertInstanceOf(ObjectDestructuringSetBinary::class, $node);
|
||||
$pair = $node->getNode('left')->getKeyValuePairs()[0];
|
||||
$this->assertSame(ConstantExpression::class, $pair['key']::class);
|
||||
$this->assertSame('name', $pair['key']->getAttribute('value'));
|
||||
$this->assertSame(AssignContextVariable::class, $pair['value']::class);
|
||||
$this->assertSame('user_name', $pair['value']->getAttribute('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTestsForString
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user