diff --git a/templating/twig_extension.rst b/templating/twig_extension.rst index 4a684718d51..4b2772d4ffb 100644 --- a/templating/twig_extension.rst +++ b/templating/twig_extension.rst @@ -58,7 +58,7 @@ Create a class that extends ``\Twig_Extension`` and fill in the logic:: `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.yml configuration `, @@ -66,6 +66,113 @@ you're done! Symfony will automatically know about your new service and add the You can now start using your filter in any Twig template. +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 ``priceFilter()`` method from the extension and update the PHP +callable defined in ``getFilters()``:: + + // src/AppBundle/Twig/AppExtension.php + namespace AppBundle\Twig; + + use AppBundle\Twig\AppRuntime; + + class AppExtension extends \Twig_Extension + { + public function getFilters() + { + return array( + // the logic of this filter is now implemented in a different class + new \Twig_SimpleFilter('price', array(AppRuntime::class, 'priceFilter')), + ); + } + } + +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 ``priceFilter()`` method:: + + // src/AppBundle/Twig/AppRuntime.php + namespace AppBundle\Twig; + + class AppRuntime + { + 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 priceFilter($number, $decimals = 0, $decPoint = '.', $thousandsSep = ',') + { + $price = number_format($number, $decimals, $decPoint, $thousandsSep); + $price = '$'.$price; + + return $price; + } + } + +Register the Lazy-Loaded Extension as a Service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Finally, register your new class as a service and tag it with ``twig.runtime`` +(and optionally inject any service needed by the Twig extension runtime): + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + services: + app.twig_runtime: + class: AppBundle\Twig\AppRuntime + public: false + tags: + - { name: twig.runtime } + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // app/config/services.php + use AppBundle\Twig\AppExtension; + + $container + ->register('app.twig_runtime', AppRuntime::class) + ->setPublic(false) + ->addTag('twig.runtime'); + .. _`Twig extensions documentation`: http://twig.sensiolabs.org/doc/advanced.html#creating-an-extension .. _`global variables`: http://twig.sensiolabs.org/doc/advanced.html#id1 .. _`functions`: http://twig.sensiolabs.org/doc/advanced.html#id2