mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-01 13:07:22 +00:00
Make embeds deterministic
This commit is contained in:
committed by
Fabien Potencier
parent
99d95dd6b8
commit
2b4aa4458a
@@ -1,6 +1,6 @@
|
||||
# 3.24.1 (2026-XX-XX)
|
||||
# 3.25.0 (2026-XX-XX)
|
||||
|
||||
* n/a
|
||||
* Use deterministic suffixes for generated embed classes
|
||||
|
||||
# 3.24.0 (2026-03-17)
|
||||
|
||||
|
||||
+16
-1
@@ -794,6 +794,21 @@ operand is contained in the right:
|
||||
You can use this operator to perform a containment test on strings,
|
||||
sequences, mappings, or objects implementing the ``Traversable`` interface.
|
||||
|
||||
.. note::
|
||||
|
||||
For sequences, mappings, and ``Traversable`` objects, ``in`` uses a loose
|
||||
comparison (similar to ``==``); use :doc:`same as <tests/sameas>` for a
|
||||
strict comparison. Like PHP's ``in_array()``, this can yield unexpected
|
||||
results when the left operand is a boolean:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# returns true because true == 'foo' under PHP loose comparison #}
|
||||
{{ true in ['foo', 'bar'] }}
|
||||
|
||||
Containment on strings only accepts string, integer, and float operands on
|
||||
the left; other types always return ``false``.
|
||||
|
||||
To perform a negative test, use the ``not in`` operator:
|
||||
|
||||
.. code-block:: twig
|
||||
@@ -1221,7 +1236,7 @@ Twig supports two modifiers:
|
||||
|
||||
* *Line whitespace trimming* via the ``~`` modifier: Removes all whitespace
|
||||
(excluding newlines). Using this modifier on the right disables the default
|
||||
removal of the first newline inherited from PHP.
|
||||
removal of the first newline mentioned above.
|
||||
|
||||
The modifiers can be used on either side of the tags like in ``{%-`` or ``-%}``
|
||||
and they consume all whitespace for that side of the tag. It is possible to use
|
||||
|
||||
+8
-2
@@ -54,6 +54,7 @@ class Parser
|
||||
private $importedSymbols;
|
||||
private $traits;
|
||||
private $embeddedTemplates = [];
|
||||
private int $lastEmbedIndex = 0;
|
||||
private $varNameSalt = 0;
|
||||
private $ignoreUnknownTwigCallables = false;
|
||||
private ExpressionParsers $parsers;
|
||||
@@ -81,8 +82,13 @@ class Parser
|
||||
*/
|
||||
public function parse(TokenStream $stream, $test = null, bool $dropNeedle = false): ModuleNode
|
||||
{
|
||||
// reset on root parse() calls only, so the counter spans nested/reentrant parses
|
||||
if (!$this->stack) {
|
||||
$this->lastEmbedIndex = 0;
|
||||
}
|
||||
|
||||
$vars = get_object_vars($this);
|
||||
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['varNameSalt']);
|
||||
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['lastEmbedIndex'], $vars['varNameSalt']);
|
||||
$this->stack[] = $vars;
|
||||
|
||||
// node visitors
|
||||
@@ -319,7 +325,7 @@ class Parser
|
||||
*/
|
||||
public function embedTemplate(ModuleNode $template)
|
||||
{
|
||||
$template->setIndex(mt_rand());
|
||||
$template->setIndex(++$this->lastEmbedIndex);
|
||||
|
||||
$this->embeddedTemplates[] = $template;
|
||||
}
|
||||
|
||||
@@ -206,6 +206,20 @@ EOF, 'index')));
|
||||
$this->assertTrue($argumentNodes->getNode(3)->getAttribute('value'));
|
||||
}
|
||||
|
||||
public function testEmbeddedTemplatesHaveSequentialIndices(): void
|
||||
{
|
||||
$template = new Source('{% embed "first" %}{% endembed %}{% embed "second" %}{% endembed %}', 'index');
|
||||
$lexer = new Lexer(new Environment(new ArrayLoader()));
|
||||
$stream = $lexer->tokenize($template);
|
||||
|
||||
$embeds = $this->getParser()
|
||||
->parse($stream)
|
||||
->getAttribute('embedded_templates');
|
||||
|
||||
$this->assertSame(1, $embeds->getNode(0)->getAttribute('index'));
|
||||
$this->assertSame(2, $embeds->getNode(1)->getAttribute('index'));
|
||||
}
|
||||
|
||||
protected function getParser()
|
||||
{
|
||||
$parser = new Parser(new Environment(new ArrayLoader()));
|
||||
|
||||
Reference in New Issue
Block a user