8278 Commits

Author SHA1 Message Date
Fabien Potencier 4b63bb1baa Remove unused PHPUnit Bridge dependency 2026-08-29 09:52:36 +02:00
Fabien Potencier 551752a92b Remove redundant data provider compatibility test 2026-08-29 09:45:29 +02:00
Fabien Potencier 768f851237 Remove obsolete PHPUnit Bridge environment variable 2026-08-29 09:41:11 +02:00
Fabien Potencier 8335e7cbaa Enable parallel PHP CS Fixer 2026-08-29 08:57:00 +02:00
Fabien Potencier ffce60f985 Update documentation version metadata 2026-08-29 08:57:00 +02:00
Fabien Potencier cabb305b5a Fix merge conflict resolution 2026-08-29 08:27:21 +02:00
Fabien Potencier f640320202 Merge branch '3.x' into 4.x
* 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
2026-08-29 00:25:20 +02:00
Fabien Potencier c32656815b minor #4908 Remove the documentation comments compilation overhead (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Remove the documentation comments compilation overhead

Documentation comments are now attached to semantic nodes during parsing, removing the dedicated AST traversal. Token parsers returning placeholder nodes can select the semantic documentation target.

Commits
-------

60eed4ccd5 Remove the documentation comments compilation overhead
2026-08-29 00:19:33 +02:00
Fabien Potencier 60eed4ccd5 Remove the documentation comments compilation overhead 2026-08-29 00:19:29 +02:00
Fabien Potencier dd0bd0ffbc minor #4904 Release destructuring temporaries after assignment (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Release destructuring temporaries after assignment

The compiled destructuring code kept the right-hand side alive in a hidden local until the end of rendering, wasting memory on large arrays and iterators. The temporary is now cleared as part of the compiled expression.

The way it works:

For this Twig expression:

```twig
{% do {name, email: address} = user %}
```

The previous generated expression was conceptually:

```php
[$context["name"], $context["address"]] = [
    getAttribute($_v0 = $context["user"], "name"),
    getAttribute($_v0, "email"),
];
```

The branch now generates:

```php
[
    [$context["name"], $context["address"]] = [
        getAttribute($_v0 = $context["user"], "name"),
        getAttribute($_v0, "email"),
    ],
    $_v0 = null,
][0]
```

The important wrapper is:

```php
[$originalExpression, $_v0 = null][0]
```

PHP evaluates array elements from left to right:

1. The original destructuring assignment runs.
2. The temporary variable is set to `null`, releasing its reference.
3. `[0]` returns the result of the original expression.

This preserves Twig’s rule that a destructuring expression returns its right-hand value.

Commits
-------

c459ef0bdd Release destructuring temporaries after assignment
2026-08-29 00:15:46 +02:00
Fabien Potencier 2450c30b49 documentation #4911 Clarify source function trust requirements (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Clarify source function trust requirements

Commits
-------

fdfef2b14a Clarify source function trust requirements
2026-08-28 19:14:06 +02:00
Fabien Potencier fdfef2b14a Clarify source function trust requirements 2026-08-28 18:11:30 +02:00
Fabien Potencier 1d081e21f8 bug #4909 Report regular expression errors from the matches operator (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Report regular expression errors from the matches operator

The `matches` operator now throws a `RuntimeError` when PCRE cannot evaluate a regular expression instead of silently treating the error as a non-match.

This makes failures such as exhausted backtrack limits visible to template authors.

Commits
-------

e5347301d7 Throw on PCRE errors in the matches operator
2026-08-28 15:10:19 +02:00
Fabien Potencier e5347301d7 Throw on PCRE errors in the matches operator 2026-08-28 08:41:42 +02:00
Fabien Potencier 0c9d0c77c0 bug #4906 Deprecate prefixed macro definedness checks (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Deprecate prefixed macro definedness checks

Testing a macro through a legacy `macro_`-prefixed name would have silently returned `false` in Twig 4.0 without ever warning; `has()` now triggers the same deprecation as `call()`.

Commits
-------

977aef7172 Deprecate prefixed macro definedness checks
2026-08-27 17:57:48 +02:00
Fabien Potencier e1223b1ea8 bug #4907 Fix duplicate macro deprecation wording (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Fix duplicate macro deprecation wording

With three or more definitions of the same macro, the deprecation mislabeled the previous duplicate as the "first definition"; it now reports "previous definition" and "new definition" lines accurately.

Commits
-------

8a37332def Fix duplicate macro deprecation wording
2026-08-27 17:57:12 +02:00
Fabien Potencier 3bc3d2e62a bug #4905 Throw when list formatting fails (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Throw when list formatting fails

`format_list` silently returned an empty string when `IntlListFormatter` fails (for instance on malformed UTF-8); it now throws a `RuntimeError` with the formatter's error message.

Commits
-------

87b930ae67 Throw when list formatting fails
2026-08-27 17:52:14 +02:00
Fabien Potencier b1ef75c954 documentation #4903 Fix documentation inaccuracies found during the 3.29 review (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Fix documentation inaccuracies found during the 3.29 review

Aligns the docs with actual behavior: `include_only` globals, `html_attr` `data-*` iterables, destructuring slot consumption and iterator reuse, a caution for the Tempest converter, `MacroNode::compile()` overrides, and a duplicated CHANGELOG entry.

Commits
-------

59f7d67848 Document that reusing a non-rewindable iterator after destructuring is unsupported
099fa3471a Document that sequence destructuring consumes one value per pattern slot
abbdf82823 Fix the html_attr documentation about iterables in data attributes
be220e6fd8 Warn about untrusted input with the default Tempest markdown converter
1205b8b6ca Document that overriding MacroNode::compile() is not supported anymore
7bd052dd91 Merge overlapping CHANGELOG entries for the destructuring fatal error fix
207f873739 Document that include_only keeps global variables available
2026-08-27 17:51:17 +02:00
Fabien Potencier 59f7d67848 Document that reusing a non-rewindable iterator after destructuring is unsupported 2026-08-27 13:43:07 +02:00
Fabien Potencier c459ef0bdd Release destructuring temporaries after assignment 2026-08-27 13:32:19 +02:00
Fabien Potencier 977aef7172 Deprecate prefixed macro definedness checks 2026-08-27 13:32:19 +02:00
Fabien Potencier 8a37332def Fix duplicate macro deprecation wording 2026-08-27 13:32:19 +02:00
Fabien Potencier 87b930ae67 Throw when list formatting fails 2026-08-27 13:32:19 +02:00
Fabien Potencier 099fa3471a Document that sequence destructuring consumes one value per pattern slot 2026-08-27 13:07:47 +02:00
Fabien Potencier abbdf82823 Fix the html_attr documentation about iterables in data attributes 2026-08-27 13:07:41 +02:00
Fabien Potencier be220e6fd8 Warn about untrusted input with the default Tempest markdown converter 2026-08-27 13:07:34 +02:00
Fabien Potencier 1205b8b6ca Document that overriding MacroNode::compile() is not supported anymore 2026-08-27 13:07:26 +02:00
Fabien Potencier 7bd052dd91 Merge overlapping CHANGELOG entries for the destructuring fatal error fix 2026-08-27 13:07:19 +02:00
Fabien Potencier 207f873739 Document that include_only keeps global variables available 2026-08-27 13:07:13 +02:00
Fabien Potencier 9a8a76c86d feature #4902 Remove lazy macro import resolution (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Remove lazy macro import resolution

Reverts the fix for #4879

This removes the unreleased lazy resolution of template-level macro imports, which introduced complex and surprising behavior around template state, blocks, interrupted renders and sandboxing.

Macros called from another template should import their dependencies inside their own body. The documentation now explains this pattern.

Commits
-------

cf971e1a59 Remove lazy macro import resolution
2026-08-27 12:17:14 +02:00
Fabien Potencier cf971e1a59 Remove lazy macro import resolution 2026-08-27 12:17:08 +02:00
Fabien Potencier d850901a18 bug #4900 Honor date formatter prototype calendars (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Honor date formatter prototype calendars

This fixes calendar selection when an `IntlDateFormatter` prototype is configured.

An explicit calendar now takes precedence, followed by the prototype calendar, with Gregorian used as the final fallback. In particular, the `TRADITIONAL` calendar is no longer mistaken for an absent value because its constant value is zero.

Commits
-------

1de0bfceb4 Honor date formatter prototype calendars
2026-08-27 08:44:30 +02:00
Fabien Potencier 1de0bfceb4 Honor date formatter prototype calendars 2026-08-27 08:44:26 +02:00
Fabien Potencier 3265884e93 bug #4899 Fix Stringable keys for ArrayAccess implementations (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Fix Stringable keys for ArrayAccess implementations

This restores support for `Stringable` keys on string-keyed `ArrayAccess` implementations such as `ArrayObject` and `ArrayIterator`, while preserving object keys for `SplObjectStorage`.

The object key is attempted first and is converted to a string only when the implementation rejects it. The optimized and strict lookup paths now share the same behavior without duplicate existence checks.

Commits
-------

f3f1649955 Fix Stringable keys for ArrayAccess implementations
2026-08-27 08:42:51 +02:00
Fabien Potencier f3f1649955 Fix Stringable keys for ArrayAccess implementations 2026-08-27 08:42:47 +02:00
Fabien Potencier 62076874e8 bug #4901 Evaluate object destructuring expressions once (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Evaluate object destructuring expressions once

This ensures the right-hand expression of an object or mapping destructuring assignment is evaluated exactly once.

All properties are now read from the same resolved value, avoiding repeated side effects and unnecessary work while preserving assignment order and return semantics.

Commits
-------

609376f491 Fix repeated object destructuring evaluation
2026-08-27 07:37:21 +02:00
Fabien Potencier 609376f491 Fix repeated object destructuring evaluation 2026-08-27 07:37:11 +02:00
Fabien Potencier 20c68c7ec2 bug #4896 Restore void return type compatibility for extension points (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Restore void return type compatibility for extension points

This restores the PHPDoc-only `void` return types on non-final extension points so subclasses written for Twig 3.28 continue to load on Twig 3.29.

Native return types remain on final classes and test methods where they are backward compatible. PHP CS Fixer is configured to preserve the compatible signatures.

Commits
-------

6bbbb49c3e Restore void return type compatibility for extension points
2026-08-27 07:27:42 +02:00
Fabien Potencier 6bbbb49c3e Restore void return type compatibility for extension points 2026-08-27 07:27:31 +02:00
Fabien Potencier 7ec1ed0a2b bug #4898 Reject destructuring patterns containing no variables (fabpot)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Reject destructuring patterns containing no variables

This rejects sequence destructuring patterns containing only empty slots, such as `[,]` and `[,,]`.

These patterns previously compiled to an empty PHP list assignment and caused an uncatchable fatal error. They now produce a Twig `SyntaxError` with the template source and line.

Commits
-------

a3a318face Reject destructuring patterns containing no variables
2026-08-27 07:18:53 +02:00
Fabien Potencier a3a318face Reject destructuring patterns containing no variables 2026-08-27 07:18:49 +02:00
Fabien Potencier 885cbdb58f feature #4895 Extract htmlAttrValue() from html_attr for standalone attribute rendering (Kocal)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Extract `htmlAttrValue()` from `html_attr` for standalone attribute rendering

The per-value resolution behind `html_attr` is extracted into a new public `HtmlExtension::htmlAttrValue()`, returning the unescaped value or `null` to omit the attribute; `html_attr()` now delegates to it, output unchanged, existing tests untouched. This lets third parties render a single attribute exactly like `html_attr` without a Twig `Environment`, since the resolution is escaper-free. symfony/ux#3820 and symfony/ux#3821 depend on this PR.

The `data-*` branch only tested `is_scalar()`, so a `\Stringable` was JSON-encoded instead of using its string representation; the same object already rendered its string form in `title` or `class`, and `AttributeValueInterface` was already excluded from that branch.

| Value in `data-value` | Before | After |
| --- | --- | --- |
| a `\Stringable` | `data-value="{}"` | `data-value="hello"` |
| a `\Stringable` that is also `JsonSerializable` | `data-value=""01JABC""` | `data-value="01JABC"` |

Commits
-------

9b18e3757d Extract `htmlAttrValue()` from `html_attr` for standalone attribute rendering
2026-08-26 16:47:06 +02:00
Hugo Alliaume 9b18e3757d Extract htmlAttrValue() from html_attr for standalone attribute rendering 2026-08-26 16:46:53 +02:00
Fabien Potencier e50f980542 bug #4894 Fix an empty destructuring pattern triggering a PHP fatal error instead of a SyntaxError (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Fix an empty destructuring pattern triggering a PHP fatal error instead of a SyntaxError

Commits
-------

a2b023397e Fix an empty destructuring pattern triggering a PHP fatal error instead of a SyntaxError
2026-08-23 11:01:57 +02:00
Fabien Potencier a2b023397e Fix an empty destructuring pattern triggering a PHP fatal error instead of a SyntaxError 2026-08-23 09:50:46 +02:00
Fabien Potencier cd25fe5b98 feature #4893 Fix array destructuring from a Traversable (iliaal, fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Fix array destructuring from a Traversable

Sequence destructuring compiled its right-hand side straight into `array_pad()`, which only accepts arrays. Destructuring from any `Traversable` crashed with an uncaught `TypeError` at render time:

```twig
{% do [a, b] = items %}
```

with `items` being e.g. an `ArrayIterator` or a generator:

```
array_pad(): Argument #1 ($array) must be of type array, ArrayIterator given
```

This change compiles the right-hand side through an `iterator_to_array()` coercion when it is a `Traversable`, matching how spread (`[...traversable]`), `merge`, and `slice` already accept Traversables:

```php
[$context["a"], $context["b"]] = array_pad(($_v0 = ($context["items"] ?? null)) instanceof \Traversable ? iterator_to_array($_v0) : $_v0, 2, null);
```

Behavior for arrays and other types is unchanged; scalars still fail as before (now via the same `array_pad` TypeError path).

Commits
-------

e2014eb92a Fix Traversable sequence destructuring semantics
9de1b3db98 Fix array destructuring from a Traversable
2026-08-23 09:46:31 +02:00
Fabien Potencier e2014eb92a Fix Traversable sequence destructuring semantics 2026-08-23 09:40:21 +02:00
Fabien Potencier 1e239fe3ed bug #4892 Register the missing extra callables in MissingExtensionSuggestor (smnandre)
This PR was squashed before being merged into the 3.x branch.

Discussion
----------

Register the missing extra callables in MissingExtensionSuggestor

`Extensions.php` mirrors what each `twig/*-extra` package declares, so `MissingExtensionSuggestor` can answer an unknown name with `try running "composer require twig/string-extra"` rather than a bare `Unknown "slug" filter`.

This PR adds the twelve callables missing from it:
* `html-extra`: `html_attr_merge` and `html_attr_type` filters, `html_cva` and  `html_attr` functions
* `intl-extra`: `format_list` filter, `language_names`, `script_names`, `country_names`, `locale_names`, `currency_names` and `timezone_names` functions
* `string-extra`: `slug`, `plural` and `singular` filters

`ExtensionsTest` checks the catalog both ways:
* every listed name resolves on an `Environment` holding the extension,
* every declared filter, function and tag is listed

Commits
-------

4212ac1303 Test extra extension catalog against local sources
dba79330db Register the missing extra callables in MissingExtensionSuggestor
2026-08-23 09:13:19 +02:00
Fabien Potencier 4212ac1303 Test extra extension catalog against local sources 2026-08-23 09:13:10 +02:00
Simon André dba79330db Register the missing extra callables in MissingExtensionSuggestor 2026-08-23 09:12:58 +02:00