* 3.x: (26 commits)
Remove the documentation comments compilation overhead
Clarify source function trust requirements
Throw on PCRE errors in the matches operator
Document that reusing a non-rewindable iterator after destructuring is unsupported
Release destructuring temporaries after assignment
Deprecate prefixed macro definedness checks
Fix duplicate macro deprecation wording
Throw when list formatting fails
Document that sequence destructuring consumes one value per pattern slot
Fix the html_attr documentation about iterables in data attributes
Warn about untrusted input with the default Tempest markdown converter
Document that overriding MacroNode::compile() is not supported anymore
Merge overlapping CHANGELOG entries for the destructuring fatal error fix
Document that include_only keeps global variables available
Remove lazy macro import resolution
Honor date formatter prototype calendars
Fix Stringable keys for ArrayAccess implementations
Fix repeated object destructuring evaluation
Restore void return type compatibility for extension points
Reject destructuring patterns containing no variables
...
# Conflicts:
# CHANGELOG
# doc/deprecated.rst
# doc/filters/format_datetime.rst
# extra/twig-extra-bundle/DependencyInjection/Compiler/MissingExtensionSuggestorPass.php
# extra/twig-extra-bundle/DependencyInjection/TwigExtraExtension.php
# extra/twig-extra-bundle/TwigExtraBundle.php
# src/MacroNamespace.php
# src/Node/MacrosNode.php
# src/Parser.php
# src/Test/IntegrationTestCase.php
# src/Test/NodeTestCase.php
# tests/CallMacroTest.php
# tests/ExpressionParserTest.php
# tests/Fixtures/macros/duplicate_definition.legacy.test
# tests/Node/MacrosTest.php
# tests/ParserTest.php
* 3.x:
Make the sandbox a first-class citizen with a dedicated Sandbox class
# Conflicts:
# CHANGELOG
# doc/deprecated.rst
# doc/tags/sandbox.rst
# phpstan-baseline.neon
# src/Extension/CoreExtension.php
# src/Extension/SandboxExtension.php
# src/Sandbox/SecurityPolicy.php
* 3.x:
Handle single-node child template bodies in cleanup
Keep captured block definitions supported
Clarify captured block deprecation wording
Simplify correctness visitor checks
Move extends validation into correctness visitor
Fix correctness visitor regressions
Fix test assertions that did not verify the intended behavior
Address review: fix block-nesting checks in CorrectnessNodeVisitor
Move the extends-in-block and extends-in-macro errors into the CorrectnessNodeVisitor
Introduce a CorrectnessNodeVisitor to validate that templates are semantically correct
Mark Markup as final
Allow calling a macro with a dynamic name via the dot operator
Add an allow-list for tests to the sandbox security policy
Fix markdown_to_html mangling content that starts with a blank line
# Conflicts:
# CHANGELOG
# doc/deprecated.rst
# doc/sandbox.rst
# src/ExpressionParser/Infix/DotExpressionParser.php
# src/Extension/CoreExtension.php
# src/Markup.php
# src/Node/CheckSecurityNode.php
# src/Node/Expression/Filter/DefaultFilter.php
# src/Node/Expression/NullCoalesceExpression.php
# src/Node/IfNode.php
# src/NodeVisitor/SandboxNodeVisitor.php
# src/Parser.php
# src/Sandbox/SecurityPolicy.php
# tests/Extension/SandboxTest.php
# tests/ParserTest.php
This PR was merged into the 3.x branch.
Discussion
----------
Allow calling a macro with a dynamic name via the dot operator
Closes#4715
Commits
-------
87093aab9e Allow calling a macro with a dynamic name via the dot operator
This PR was merged into the 3.x branch.
Discussion
----------
Add an allow-list for tests to the sandbox security policy
Commits
-------
416d07da1d Add an allow-list for tests to the sandbox security policy
* 3.x:
Document how to customize the markdown_to_html converter
Make the include() function return a Markup object
Fix nested block() resolution when a directly rendered block calls parent()
Fix nested block() resolution when a directly rendered block calls parent()
Document storing an enum in a variable to avoid repeating its FQCN
Stop reporting a skipped test in IntegrationTestCase when there is no legacy test to run
Document {#--#} as the replacement for the deprecated spaceless filter
Skip the string cast in PrintNode when the expression is already a string and add tests
Ensure PrintNode is yielding string content
CoreExtension::getAttribute: small improvement regarding getter/isser/hasser
# Conflicts:
# CHANGELOG
# tests/Node/ForTest.php
* 3.x: (23 commits)
Bump version
Prepare the 3.26.0 release
Update CHANGELOG
Document that the sandbox doesn't protect against resource exhaustion
Document template_from_string caveats when used in a sandboxed env
Pre-escape HTML input on the `spaceless` filter
Add docs on Markup about the goal of this class in the context of a sandbox
Fix sandbox bypass in the "column" filter
Fix sandbox `__toString` bypasses
Validate macro name in MacroReferenceExpression constructor
Fix sandbox bypass: PHP code injection via _self / import macro reference
Fix deprecations in tests
Fix sandbox bypass in the `{% sandbox %}` tag when including a preloaded template
Encode single quotes as \x27 in Compiler::string()
Fix sandbox bypass: PHP code injection via {% use %} template name
Fix unbounded memoisation of `IntlDateFormatter` / `NumberFormatter`
Fix deprecation
[Profiler] Escape template and profile names in HtmlDumper
Bump version
Fix sandbox bypass: propagate sandbox state to checkArrow for source-policy sandboxing
...
# Conflicts:
# CHANGELOG
# doc/filters/spaceless.rst
# extra/cssinliner-extra/CssInlinerExtension.php
# extra/inky-extra/InkyExtension.php
# extra/markdown-extra/MarkdownExtension.php
# src/Environment.php
# src/ExpressionParser/Infix/DotExpressionParser.php
# src/Extension/CoreExtension.php
# src/Node/Expression/FilterExpression.php
# src/Node/Expression/FunctionExpression.php
# src/Node/Expression/TestExpression.php
# src/Node/ModuleNode.php
# src/NodeVisitor/SandboxNodeVisitor.php
# src/Resources/core.php
# src/TokenParser/SandboxTokenParser.php
# tests/Extension/SandboxTest.php
The name passed to MacroReferenceExpression is emitted as raw PHP in
compile() via "->{$name}(...)". Callers were expected to validate
the name, but a missing check led to CVE-2026-XXXXX (PHP code injection
via _self / import macro reference): defense-in-depth, validate the
name in the constructor so the class is safe by construction.
* origin/3.x:
Add a `needs_is_sandboxed` option for filters, functions, and tests
Bump version
Make embeds deterministic
[Doc] Document loose comparison in the `in` operator
[Doc] Reword whitespace control note about first-newline removal
Stop publishing extra package minor versions with no changes
Lazy load EscaperRuntime in EscaperExtension
Fix typo
Replace parent-child analogy in `doc/tags/extends.rst`
doc: Add missing toctree entries and fix ordering
Fix CHANGELOG
Bump version
Prepare the 3.24.0 release
* 3.x:
Update CHANGELOG
Add `html_attr_relaxed` escaping strategy
re-add mixed return type
Support short-circuiting in null-safe operator chains
Add support for renaming variables in object destructuring
Update .gitattributes to remove splitsh.json
Fix intro for operator precedence table ?
This PR was merged into the 3.x branch.
Discussion
----------
Support short-circuiting in null-safe operator chains
This PR adds short-circuiting for null-safe operator chains, using the same rules as PHP, `PropertyAccess`, and the `ExpressionLanguage`.
Previously, only the immediate null-safe access was guarded. With this change, as soon as a `null` is encountered at a null-safe access, the rest of the chain is skipped.
My approach was to move the null check outside of the `getAttribute()` calls so the expression can immediately return `null`, eg:
```twig
foo?.bar.baz
```
Before:
```php
yield $this->env
->getRuntime('Twig\Runtime\EscaperRuntime')
->escape(
CoreExtension::getAttribute(
$this->env,
$this->source,
(
null === (
$_v0 = (
isset($context['foo']) || array_key_exists('foo', $context)
? $context['foo']
: throw new RuntimeError('Variable "foo" does not exist.', 3, $this->source)
)
)
? null
: CoreExtension::getAttribute(
$this->env,
$this->source,
$_v0,
'bar',
[],
'any',
false,
false,
false,
3
)
),
'baz',
[],
'any',
false,
false,
false,
3
),
'html',
null,
true
);
```
Now:
```php
yield $this->env
->getRuntime('Twig\Runtime\EscaperRuntime')
->escape(
(
null === (
$_v0 = (
isset($context['foo']) || array_key_exists('foo', $context)
? $context['foo']
: throw new RuntimeError('Variable "foo" does not exist.', 3, $this->source)
)
)
? null
: CoreExtension::getAttribute(
$this->env,
$this->source,
CoreExtension::getAttribute(
$this->env,
$this->source,
$_v0,
'bar',
[],
'any',
false,
false,
false,
3
),
'baz',
[],
'any',
false,
false,
false,
3
)
),
'html',
null,
true
);
```
Commits
-------
d56e8e2dba Support short-circuiting in null-safe operator chains
* 3.x:
Update CHANGELOG
Fix accessing arrays with stringable objects as key
Update inky_to_html.rst: Updating link
Update replace.rst
[Doc] Tweaks in the escaping article
Compile 'index' with repr (not string) in EmbedNode
Introduce registerUndefinedTestCallback
Fix intl test
Bump minimum Commonmark requirement
Support two words test guard
Bump version
Improve documentation examples for `enum` and `enum_cases`
Avoid errors when failing to guess the template info for an error
Add note to format_datetime explaining how to install required extensions
Fix compatibility layer