From 5d4bd1baf4a48dd445288925516ad3f0ea110e5b Mon Sep 17 00:00:00 2001 From: itsalmostchristmas <282220018+itsalmostchristmas@users.noreply.github.com> Date: Wed, 6 May 2026 14:55:26 +0200 Subject: [PATCH 1/4] make embeds deterministic --- src/Parser.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Parser.php b/src/Parser.php index 3553007a95e..e7c558d2c67 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -42,6 +42,7 @@ */ class Parser { + private static int $embedIndex = 0; private $stack = []; private ?\WeakMap $expressionRefs = null; private $stream; @@ -319,7 +320,7 @@ public function hasTraits(): bool */ public function embedTemplate(ModuleNode $template) { - $template->setIndex(mt_rand()); + $template->setIndex(++self::$embedIndex); $this->embeddedTemplates[] = $template; } From 90749dca529ea1151ece4ee7942b02d962612b23 Mon Sep 17 00:00:00 2001 From: itsalmostchristmas <282220018+itsalmostchristmas@users.noreply.github.com> Date: Wed, 6 May 2026 21:09:13 +0200 Subject: [PATCH 2/4] use per-root indices for embedded templates --- src/Parser.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index e7c558d2c67..2012e77be60 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -42,7 +42,6 @@ */ class Parser { - private static int $embedIndex = 0; private $stack = []; private ?\WeakMap $expressionRefs = null; private $stream; @@ -55,6 +54,7 @@ class Parser private $importedSymbols; private $traits; private $embeddedTemplates = []; + private int $nextEmbedIndex = 1; private $varNameSalt = 0; private $ignoreUnknownTwigCallables = false; private ExpressionParsers $parsers; @@ -84,6 +84,12 @@ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = fals { $vars = get_object_vars($this); unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['varNameSalt']); + + // restore on root modules only + if (0 < \count($this->stack)) { + unset($vars['nextEmbedIndex']); + } + $this->stack[] = $vars; // node visitors @@ -320,7 +326,7 @@ public function hasTraits(): bool */ public function embedTemplate(ModuleNode $template) { - $template->setIndex(++self::$embedIndex); + $template->setIndex($this->nextEmbedIndex++); $this->embeddedTemplates[] = $template; } From 300b68e7f1b46831fc14f9cb5a85e525e52b982d Mon Sep 17 00:00:00 2001 From: itsalmostchristmas <282220018+itsalmostchristmas@users.noreply.github.com> Date: Thu, 7 May 2026 11:18:09 +0200 Subject: [PATCH 3/4] move nextEmbedIndex out of stack --- src/Parser.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 2012e77be60..9363763dae2 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -83,13 +83,7 @@ public function getVarName(): string public function parse(TokenStream $stream, $test = null, bool $dropNeedle = false): ModuleNode { $vars = get_object_vars($this); - unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['varNameSalt']); - - // restore on root modules only - if (0 < \count($this->stack)) { - unset($vars['nextEmbedIndex']); - } - + unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['nextEmbedIndex'], $vars['varNameSalt']); $this->stack[] = $vars; // node visitors @@ -149,6 +143,11 @@ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = fals $this->$key = $val; } + // restore on root modules only + if (!$this->stack) { + $this->nextEmbedIndex = 1; + } + return $node; } From 698ea1398a31bc10be317366068bebc314cfd327 Mon Sep 17 00:00:00 2001 From: itsalmostchristmas <282220018+itsalmostchristmas@users.noreply.github.com> Date: Thu, 7 May 2026 12:56:04 +0200 Subject: [PATCH 4/4] reset nextEmbedIndex at start of parse() --- src/Parser.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 9363763dae2..3510601706f 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -82,6 +82,11 @@ public function getVarName(): string */ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = false): ModuleNode { + // restore on root modules only + if (!$this->stack) { + $this->nextEmbedIndex = 1; + } + $vars = get_object_vars($this); unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['nextEmbedIndex'], $vars['varNameSalt']); $this->stack[] = $vars; @@ -143,11 +148,6 @@ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = fals $this->$key = $val; } - // restore on root modules only - if (!$this->stack) { - $this->nextEmbedIndex = 1; - } - return $node; }