@@ -1553,23 +1553,20 @@ as currency:
15531553 {# pass in the 3 optional arguments #}
15541554 {{ product.price|price(2, ',', '.') }}
15551555
1556- Create a class that extends ``AbstractExtension `` and fill in the logic::
1556+ .. _templates-twig-filter-attribute :
1557+
1558+ Create a class with a method that contains the filter logic, then add
1559+ the ``#[AsTwigFilter] `` attribute to define the name and options of
1560+ the Twig filter::
15571561
15581562 // src/Twig/AppExtension.php
15591563 namespace App\Twig;
15601564
1561- use Twig\Extension\AbstractExtension;
1562- use Twig\TwigFilter;
1565+ use Twig\Attribute\AsTwigFilter;
15631566
1564- class AppExtension extends AbstractExtension
1567+ class AppExtension
15651568 {
1566- public function getFilters(): array
1567- {
1568- return [
1569- new TwigFilter('price', [$this, 'formatPrice']),
1570- ];
1571- }
1572-
1569+ #[AsTwigFilter('price')]
15731570 public function formatPrice(float $number, int $decimals = 0, string $decPoint = '.', string $thousandsSep = ','): string
15741571 {
15751572 $price = number_format($number, $decimals, $decPoint, $thousandsSep);
@@ -1579,24 +1576,19 @@ Create a class that extends ``AbstractExtension`` and fill in the logic::
15791576 }
15801577 }
15811578
1582- If you want to create a function instead of a filter, define the
1583- ``getFunctions() `` method::
1579+ .. _templates-twig-function-attribute :
1580+
1581+ If you want to create a function instead of a filter, use the
1582+ ``#[AsTwigFunction] `` attribute::
15841583
15851584 // src/Twig/AppExtension.php
15861585 namespace App\Twig;
15871586
1588- use Twig\Extension\AbstractExtension;
1589- use Twig\TwigFunction;
1587+ use Twig\Attribute\AsTwigFunction;
15901588
1591- class AppExtension extends AbstractExtension
1589+ class AppExtension
15921590 {
1593- public function getFunctions(): array
1594- {
1595- return [
1596- new TwigFunction('area', [$this, 'calculateArea']),
1597- ];
1598- }
1599-
1591+ #[AsTwigFunction('area')]
16001592 public function calculateArea(int $width, int $length): int
16011593 {
16021594 return $width * $length;
@@ -1608,6 +1600,16 @@ If you want to create a function instead of a filter, define the
16081600 Along with custom filters and functions, you can also register
16091601 `global variables `_.
16101602
1603+ .. versionadded :: 7.3
1604+
1605+ Support for the ``#[AsTwigFilter] ``, ``#[AsTwigFunction] `` and ``#[AsTwigTest] `` attributes was introduced in Symfony 7.3.
1606+ Previously, you had to extend the ``AbstractExtension `` class, and override the
1607+ ``getFilters() `` and ``getFunctions() `` methods.
1608+
1609+ When using autoconfiguration, the tag ``twig.attribute_extension `` is added automatically
1610+ when a Twig attribute is used on a method of a class. Otherwise, when autoconfiguration is not enabled,
1611+ it needs to be added in the service definition.
1612+
16111613Register an Extension as a Service
16121614..................................
16131615
@@ -1631,10 +1633,10 @@ this command to confirm that your new filter was successfully registered:
16311633Creating Lazy-Loaded Twig Extensions
16321634~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16331635
1634- Including the code of the custom filters/functions in the Twig extension class
1635- is the simplest way to create extensions. However, Twig must initialize all
1636- extensions before rendering any template, even if the template doesn't use an
1637- extension.
1636+ When using attributes to extend Twig, the services are initialized only when
1637+ the functions or filters are used to render the template. But in case you use the
1638+ classic approach by extending the `` AbstractExtension `` class, Twig initializes all the extensions before
1639+ rendering any template, even if the extension is not used in the template .
16381640
16391641If extensions don't define dependencies (i.e. if you don't inject services in
16401642them) performance is not affected. However, if extensions define lots of complex
0 commit comments