mirror of
https://github.com/symfony/symfony-docs.git
synced 2026-03-24 00:32:14 +01:00
182 lines
5.7 KiB
ReStructuredText
182 lines
5.7 KiB
ReStructuredText
.. index::
|
|
single: Twig extensions
|
|
|
|
How to Write a custom Twig Extension
|
|
====================================
|
|
|
|
`Twig Extensions`_ allow to create custom Twig functions, filters and more to
|
|
use them in your templates.
|
|
|
|
Before writing your own Twig extension, check if the filter/function that you
|
|
need is already implemented in the `default Twig filters and functions`_ or the
|
|
:doc:`Twig filters and functions added by Symfony </reference/twig_reference>`.
|
|
Check also the `official Twig extensions`_, which add commonly needed filters
|
|
and functions and can be installed in your application as follows:
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require twig/extensions
|
|
|
|
Create the Extension Class
|
|
--------------------------
|
|
|
|
Suppose you want to create a new filter called ``price`` that formats a number
|
|
into money:
|
|
|
|
.. code-block:: twig
|
|
|
|
{{ product.price|price }}
|
|
|
|
{# pass in the 3 optional arguments #}
|
|
{{ product.price|price(2, ',', '.') }}
|
|
|
|
Create a class that extends ``AbstractExtension`` and fill in the logic::
|
|
|
|
// src/Twig/AppExtension.php
|
|
namespace App\Twig;
|
|
|
|
use Twig\Extension\AbstractExtension;
|
|
use Twig\TwigFilter;
|
|
|
|
class AppExtension extends AbstractExtension
|
|
{
|
|
public function getFilters()
|
|
{
|
|
return [
|
|
new TwigFilter('price', [$this, 'formatPrice']),
|
|
];
|
|
}
|
|
|
|
public function formatPrice($number, $decimals = 0, $decPoint = '.', $thousandsSep = ',')
|
|
{
|
|
$price = number_format($number, $decimals, $decPoint, $thousandsSep);
|
|
$price = '$'.$price;
|
|
|
|
return $price;
|
|
}
|
|
}
|
|
|
|
If you want to create a function instead of a filter, define the
|
|
``getFunctions()`` method::
|
|
|
|
// src/Twig/AppExtension.php
|
|
namespace App\Twig;
|
|
|
|
use Twig\Extension\AbstractExtension;
|
|
use Twig\TwigFunction;
|
|
|
|
class AppExtension extends AbstractExtension
|
|
{
|
|
public function getFunctions()
|
|
{
|
|
return [
|
|
new TwigFunction('area', [$this, 'calculateArea']),
|
|
];
|
|
}
|
|
|
|
public function calculateArea(int $width, int $length)
|
|
{
|
|
return $width * $length;
|
|
}
|
|
}
|
|
|
|
.. tip::
|
|
|
|
Along with custom filters and functions, you can also register
|
|
`global variables`_.
|
|
|
|
Register an Extension as a Service
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Next, register your class as a service and tag it with ``twig.extension``. If you're
|
|
using the :ref:`default services.yaml configuration <service-container-services-load-example>`,
|
|
you're done! Symfony will automatically know about your new service and add the tag.
|
|
|
|
You can now start using your filter in any Twig template. Optionally, execute
|
|
this command to confirm that your new filter was successfully registered:
|
|
|
|
.. code-block:: terminal
|
|
|
|
# display all information about Twig
|
|
$ php bin/console debug:twig
|
|
|
|
# display only the information about a specific filter
|
|
$ php bin/console debug:twig --filter=price
|
|
|
|
.. _lazy-loaded-twig-extensions:
|
|
|
|
Creating Lazy-Loaded Twig Extensions
|
|
------------------------------------
|
|
|
|
.. versionadded:: 1.26
|
|
|
|
Support for lazy-loaded extensions was introduced in Twig 1.26.
|
|
|
|
Including the code of the custom filters/functions in the Twig extension class
|
|
is the simplest way to create extensions. However, Twig must initialize all
|
|
extensions before rendering any template, even if the template doesn't use an
|
|
extension.
|
|
|
|
If extensions don't define dependencies (i.e. if you don't inject services in
|
|
them) performance is not affected. However, if extensions define lots of complex
|
|
dependencies (e.g. those making database connections), the performance loss can
|
|
be significant.
|
|
|
|
That's why Twig allows to decouple the extension definition from its
|
|
implementation. Following the same example as before, the first change would be
|
|
to remove the ``formatPrice()`` method from the extension and update the PHP
|
|
callable defined in ``getFilters()``::
|
|
|
|
// src/Twig/AppExtension.php
|
|
namespace App\Twig;
|
|
|
|
use App\Twig\AppRuntime;
|
|
use Twig\Extension\AbstractExtension;
|
|
use Twig\TwigFilter;
|
|
|
|
class AppExtension extends AbstractExtension
|
|
{
|
|
public function getFilters()
|
|
{
|
|
return [
|
|
// the logic of this filter is now implemented in a different class
|
|
new TwigFilter('price', [AppRuntime::class, 'formatPrice']),
|
|
];
|
|
}
|
|
}
|
|
|
|
Then, create the new ``AppRuntime`` class (it's not required but these classes
|
|
are suffixed with ``Runtime`` by convention) and include the logic of the
|
|
previous ``formatPrice()`` method::
|
|
|
|
// src/Twig/AppRuntime.php
|
|
namespace App\Twig;
|
|
|
|
use Twig\Extension\RuntimeExtensionInterface;
|
|
|
|
class AppRuntime implements RuntimeExtensionInterface
|
|
{
|
|
public function __construct()
|
|
{
|
|
// this simple example doesn't define any dependency, but in your own
|
|
// extensions, you'll need to inject services using this constructor
|
|
}
|
|
|
|
public function formatPrice($number, $decimals = 0, $decPoint = '.', $thousandsSep = ',')
|
|
{
|
|
$price = number_format($number, $decimals, $decPoint, $thousandsSep);
|
|
$price = '$'.$price;
|
|
|
|
return $price;
|
|
}
|
|
}
|
|
|
|
If you're using the default ``services.yaml`` configuration, this will already
|
|
work! Otherwise, :ref:`create a service <service-container-creating-service>`
|
|
for this class and :doc:`tag your service </service_container/tags>` with ``twig.runtime``.
|
|
|
|
.. _`Twig Extensions`: https://twig.symfony.com/doc/2.x/advanced.html#creating-an-extension
|
|
.. _`default Twig filters and functions`: https://twig.symfony.com/doc/2.x/#reference
|
|
.. _`official Twig extensions`: https://github.com/twigphp/Twig-extensions
|
|
.. _`global variables`: https://twig.symfony.com/doc/2.x/advanced.html#id1
|