Skip to content

Commit 10eb74e

Browse files
Prevent shorthand modifier tag pair modifiers from being evaluated twice (#5828)
1 parent 629c7b2 commit 10eb74e

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

src/View/Antlers/Language/Runtime/NodeProcessor.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,15 @@ public function reduce($processNodes)
16321632
$runtimeResult = $environment->evaluate($node->parsedRuntimeNodes);
16331633
$this->data = $restoreData;
16341634

1635+
// If the environment processed modifiers for the current node
1636+
// and the node does _not_ have parameters, we will set the
1637+
// $runtimeResolveModifiedValue flag to true to prevent
1638+
// the NodeProcessor from attempting to evaluate the
1639+
// modifier chain again down below before loops.
1640+
if (! $node->hasParameters && $environment->getDidEvaluateModifiers()) {
1641+
$runtimeResolveModifiedValue = true;
1642+
}
1643+
16351644
if (is_string($runtimeResult) && $node->hasProcessedInterpolationRegions) {
16361645
$interpolationScope = $this->getActiveData();
16371646

src/View/Antlers/Language/Runtime/Sandbox/Environment.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class Environment
9191
protected $interpolationKeys = [];
9292
protected $assignments = [];
9393
protected $dataManagerInterpolations = [];
94+
protected $evaluatedModifiers = false;
9495

9596
/**
9697
* @var LanguageOperatorManager|null
@@ -309,6 +310,8 @@ public function processStatements($statements)
309310
*/
310311
public function evaluate($nodes)
311312
{
313+
$this->evaluatedModifiers = false;
314+
312315
if (count($nodes) == 0) {
313316
return null;
314317
}
@@ -1241,9 +1244,16 @@ private function getFallbackComparisonValue($val)
12411244
*/
12421245
private function applyModifiers($value, ModifierChainNode $modifierChain)
12431246
{
1247+
$this->evaluatedModifiers = true;
1248+
12441249
return ModifierManager::evaluate($value, $this, $modifierChain, $this->data);
12451250
}
12461251

1252+
public function getDidEvaluateModifiers()
1253+
{
1254+
return $this->evaluatedModifiers;
1255+
}
1256+
12471257
/**
12481258
* Adjusts the value based on the current environment state.
12491259
*

tests/Antlers/Runtime/LoopTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,35 @@ public function test_runtime_resets_data_manager_paired_state()
145145
$this->assertSame($expected, trim($this->renderString($template, $data, true)));
146146
$this->assertTrue($isPaired);
147147
}
148+
149+
public function test_runtime_does_not_attempt_evaluate_modifiers_twice()
150+
{
151+
mt_srand(1234);
152+
153+
$data = [
154+
'widths' => [
155+
'25',
156+
'50',
157+
'75',
158+
],
159+
];
160+
161+
$template = <<<'EOT'
162+
{{ loop from="1" to="10" }}<{{ value }}><{{ widths | shuffle | limit:1 }}width-{{ value }}{{ /widths }}><{{ value }}>{{ unless last }}|{{ /unless}}{{ /loop }}
163+
EOT;
164+
165+
$expected = <<<'EXPECTED'
166+
<1><width-75><1>|<2><width-75><2>|<3><width-50><3>|<4><width-75><4>|<5><width-25><5>|<6><width-75><6>|<7><width-75><7>|<8><width-50><8>|<9><width-50><9>|<10><width-50><10>
167+
EXPECTED;
168+
169+
$this->assertSame($expected, $this->renderString($template, $data, true));
170+
171+
mt_srand(1234);
172+
173+
$template = <<<'EOT'
174+
{{ loop from="1" to="10" }}<{{ value }}><{{ widths | shuffle | limit:1 }}width-{{ value }}{{ /widths | shuffle | limit:1 }}><{{ value }}>{{ unless last }}|{{ /unless }}{{ /loop }}
175+
EOT;
176+
177+
$this->assertSame($expected, $this->renderString($template, $data, true));
178+
}
148179
}

0 commit comments

Comments
 (0)