diff --git a/_build/redirection_map b/_build/redirection_map index f9ec4237331..5594141967e 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -446,3 +446,13 @@ /form/action_method /forms /reference/requirements /setup /bundles/inheritance /bundles/override +/templating /templates +/templating/escaping /templates +/templating/syntax /templates +/templating/debug /templates +/templating/render_without_controller /templates +/templating/app_variable /templates +/templating/formats /templates +/templating/namespaced_paths /templates +/templating/embedding_controllers /templates +/templating/inheritance /templates diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 3a728812b07..5db716ecdf9 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -57,6 +57,8 @@ which is almost equivalent to the more verbose, but also more flexible, $_SERVER ); +.. _accessing-request-data: + Accessing Request Data ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/templating.rst b/components/templating.rst index ea6b8d11e83..a104ea3e1d8 100644 --- a/components/templating.rst +++ b/components/templating.rst @@ -28,8 +28,8 @@ Usage .. seealso:: This article explains how to use the Templating features as an independent - component in any PHP application. Read the :doc:`/templating` article to - learn about how to work with templates in Symfony applications. + component in any PHP application. Read the article about :doc:`templates ` + to learn about how to work with templates in Symfony applications. The :class:`Symfony\\Component\\Templating\\PhpEngine` class is the entry point of the component. It needs a @@ -211,5 +211,5 @@ Learn More :glob: /components/templating/* - /templating + /templates /templating/* diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index d986d7471b7..bdeac5ed93d 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -123,6 +123,8 @@ new kernel. .. index:: single: Configuration; Debug mode +.. _debug-mode: + Debug Mode ~~~~~~~~~~ diff --git a/controller.rst b/controller.rst index 2513b5d3faf..879c984bfc8 100644 --- a/controller.rst +++ b/controller.rst @@ -179,7 +179,7 @@ object for you:: return $this->render('lucky/number.html.twig', ['number' => $number]); Templating and Twig are explained more in the -:doc:`Creating and Using Templates article `. +:doc:`Creating and Using Templates article `. .. index:: single: Controller; Accessing services @@ -461,7 +461,8 @@ and then redirects. The message key (``notice`` in this example) can be anything you'll use this key to retrieve the message. In the template of the next page (or even better, in your base layout template), -read any flash messages from the session using ``app.flashes()``: +read any flash messages from the session using the ``flashes()`` method provided +by the :ref:`Twig global app variable `: .. code-block:: html+twig @@ -650,7 +651,7 @@ handle caching and more. Keep Going! ----------- -Next, learn all about :doc:`rendering templates with Twig `. +Next, learn all about :doc:`rendering templates with Twig `. Learn more about Controllers ---------------------------- @@ -658,7 +659,7 @@ Learn more about Controllers .. toctree:: :hidden: - templating + templates .. toctree:: :maxdepth: 1 diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 9ba1850d58d..c1c7d1c6f95 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -206,9 +206,9 @@ Request Events, Checking Types ------------------------------ A single page can make several requests (one master request, and then multiple -sub-requests - typically by :doc:`/templating/embedding_controllers`). For the core -Symfony events, you might need to check to see if the event is for a "master" request -or a "sub request":: +sub-requests - typically when :ref:`embedding controllers in templates `). +For the core Symfony events, you might need to check to see if the event is for +a "master" request or a "sub request":: // src/EventListener/RequestListener.php namespace App\EventListener; diff --git a/getting_started/index.rst b/getting_started/index.rst index acd7ddc5dcd..a14f36f4cd2 100644 --- a/getting_started/index.rst +++ b/getting_started/index.rst @@ -8,5 +8,5 @@ Getting Started /page_creation /routing /controller - /templating + /templates /configuration diff --git a/http_cache/esi.rst b/http_cache/esi.rst index 295a84b2816..1dd9540361f 100644 --- a/http_cache/esi.rst +++ b/http_cache/esi.rst @@ -114,8 +114,8 @@ independently of the rest of the page:: In this example, the full-page cache has a lifetime of ten minutes. Next, include the news ticker in the template by embedding an action. -This is done via the ``render`` helper (see :doc:`/templating/embedding_controllers` -for more details). +This is done via the ``render()`` helper (for more details, see how to +:ref:`embed controllers in templates `). As the embedded content comes from another page (or controller for that matter), Symfony uses the standard ``render`` helper to configure ESI tags: diff --git a/introduction/from_flat_php_to_symfony.rst b/introduction/from_flat_php_to_symfony.rst index 63b32c5ed8d..6e4b07a48c9 100644 --- a/introduction/from_flat_php_to_symfony.rst +++ b/introduction/from_flat_php_to_symfony.rst @@ -532,7 +532,7 @@ a simple application. Along the way, you've made a simple routing system and a method using ``ob_start()`` and ``ob_get_clean()`` to render templates. If, for some reason, you needed to continue building this "framework" from scratch, you could at least use Symfony's standalone -:doc:`Routing ` component and :doc:`Twig `, +:doc:`Routing ` component and :doc:`Twig `, which already solve these problems. Instead of re-solving common problems, you can let Symfony take care of diff --git a/mailer.rst b/mailer.rst index b2849b35b90..adb367f1996 100644 --- a/mailer.rst +++ b/mailer.rst @@ -291,7 +291,7 @@ create an event subscriber to set it automatically:: Twig: HTML & CSS ---------------- -The Mime component integrates with the :doc:`Twig template engine ` +The Mime component integrates with the :ref:`Twig template engine ` to provide advanced features such as CSS style inlining and support for HTML/CSS frameworks to create complex HTML email messages. First, make sure Twig is installed: diff --git a/page_creation.rst b/page_creation.rst index 4dd1d0eb335..82cfdc84e1c 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -251,8 +251,8 @@ Now you may wonder where the Web Debug Toolbar has gone: that's because there is no ```` tag in the current template. You can add the body element yourself, or extend ``base.html.twig``, which contains all default HTML elements. -In the :doc:`/templating` article, you'll learn all about Twig: how to loop, render -other templates and leverage its powerful layout inheritance system. +In the :doc:`templates ` article, you'll learn all about Twig: how +to loop, render other templates and leverage its powerful layout inheritance system. Checking out the Project Structure ---------------------------------- @@ -304,7 +304,7 @@ Ok, time to finish mastering the fundamentals by reading these articles: * :doc:`/routing` * :doc:`/controller` -* :doc:`/templating` +* :doc:`/templates` * :doc:`/configuration` Then, learn about other important topics like the diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index aa5f1a032fb..147a8a9b145 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -5,8 +5,8 @@ Twig Configuration Reference (TwigBundle) ========================================= The TwigBundle integrates the Twig library in Symfony applications to -:doc:`render templates `. All these options are configured under -the ``twig`` key in your application configuration. +:ref:`render templates `. All these options are configured +under the ``twig`` key in your application configuration. .. code-block:: terminal @@ -41,8 +41,10 @@ Configuration * `timezone`_ * `debug`_ +* `default_path`_ * `exception_controller`_ * `form_themes`_ +* `globals`_ * `number_format`_ * `decimals`_ @@ -62,6 +64,8 @@ If ``true``, whenever a template is rendered, Symfony checks first if its source code has changed since it was compiled. If it has changed, the template is compiled again automatically. +.. _config-twig-autoescape: + autoescape ~~~~~~~~~~ @@ -73,7 +77,7 @@ individually in the templates). .. caution:: Setting this option to ``false`` is dangerous and it will make your - application vulnerable to XSS exploits because most third-party bundles + application vulnerable to `XSS attacks`_ because most third-party bundles assume that auto-escaping is enabled and they don't escape contents themselves. @@ -139,8 +143,8 @@ charset **type**: ``string`` **default**: ``'%kernel.charset%'`` The charset used by the template files. By default it's the same as the value of -the ``kernel.charset`` container parameter, which is ``UTF-8`` by default in -Symfony applications. +the :ref:`kernel.charset container parameter `, +which is ``UTF-8`` by default in Symfony applications. date ~~~~ @@ -181,6 +185,17 @@ debug If ``true``, the compiled templates include a ``__toString()`` method that can be used to display their nodes. +.. _config-twig-default-path: + +default_path +~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``'%kernel.project_dir%/templates'`` + +The path to the directory where Symfony will look for the application Twig +templates by default. If you store the templates in more than one directory, use +the :ref:`paths ` option too. + .. _config-twig-exception-controller: exception_controller @@ -195,7 +210,8 @@ is what's responsible for rendering specific templates under different error conditions (see :doc:`/controller/error_pages`). Modifying this option is advanced. If you need to customize an error page you should use the previous link. If you need to perform some behavior on an exception, -you should add a listener to the ``kernel.exception`` event (see :ref:`dic-tags-kernel-event-listener`). +you should add an :doc:`event listener ` to the +:ref:`kernel.exception event `. .. _config-twig-form-themes: @@ -253,6 +269,14 @@ These global themes are applied to all forms, even those which use the :ref:`form_theme Twig tag `, but you can :ref:`disable global themes for specific forms `. +globals +~~~~~~~ + +**type**: ``array`` **default**: ``[]`` + +It defines the global variables injected automatically into all Twig templates. +Learn more about :doc:`Twig global variables `. + number_format ~~~~~~~~~~~~~ @@ -301,15 +325,6 @@ on. Set it to ``0`` to disable all the optimizations. You can even enable or disable these optimizations selectively, as explained in the Twig documentation about `the optimizer extension`_. -.. _config-twig-default-path: - -default_path -~~~~~~~~~~~~ - -**type**: ``string`` **default**: ``'%kernel.project_dir%/templates'`` - -The default directory where Symfony will look for Twig templates. - .. _config-twig-paths: paths @@ -317,23 +332,8 @@ paths **type**: ``array`` **default**: ``null`` -.. deprecated:: 4.2 - - Using the ``src/Resources/views/`` directory to store templates was - deprecated in Symfony 4.2. Use instead the directory defined in the - ``default_path`` option (which is ``templates/`` by default). - -This option defines the directories where Symfony will look for Twig templates -in addition to the default locations. Symfony looks for the templates in the -following order: - -#. The directories defined in this option; -#. The ``Resources/views/`` directories of the bundles used in the application; -#. The ``src/Resources/views/`` directory of the application; -#. The directory defined in the ``default_path`` option. - -The values of the ``paths`` option are defined as ``key: value`` pairs where the -``value`` part can be ``null``. For example: +Defines the directories where application templates are stored in addition to +the directory defined in the :ref:`default_path option `: .. configuration-block:: @@ -343,7 +343,8 @@ The values of the ``paths`` option are defined as ``key: value`` pairs where the twig: # ... paths: - '%kernel.project_dir%/vendor/acme/foo-bar/templates': ~ + 'email/default/templates': ~ + 'backend/templates': 'admin' .. code-block:: xml @@ -357,7 +358,8 @@ The values of the ``paths`` option are defined as ``key: value`` pairs where the - %kernel.project_dir%/vendor/acme/foo-bar/templates + email/default/templates + backend/templates @@ -367,60 +369,12 @@ The values of the ``paths`` option are defined as ``key: value`` pairs where the $container->loadFromExtension('twig', [ // ... 'paths' => [ - '%kernel.project_dir%/vendor/acme/foo-bar/templates' => null, + 'email/default/templates' => null, + 'backend/templates' => 'admin', ], ]); -The directories defined in the ``paths`` option have more priority than the -default directories defined by Symfony. In the above example, if the template -exists in the ``acme/foo-bar/templates/`` directory inside your application's -``vendor/``, it will be used by Symfony. - -If you provide a value for any path, Symfony will consider it the Twig namespace -for that directory: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/twig.yaml - twig: - # ... - paths: - '%kernel.project_dir%/vendor/acme/foo-bar/templates': 'foo_bar' - - .. code-block:: xml - - - - - - - %kernel.project_dir%/vendor/acme/foo-bar/templates - - - - .. code-block:: php - - # config/packages/twig.php - $container->loadFromExtension('twig', [ - // ... - 'paths' => [ - '%kernel.project_dir%/vendor/acme/foo-bar/templates' => 'foo_bar', - ], - ]); - -This option is useful to not mess with the default template directories defined -by Symfony. Besides, it simplifies how you refer to those templates: - -.. code-block:: text - - @foo_bar/template_name.html.twig +Read more about :ref:`template directories and namespaces `. strict_variables ~~~~~~~~~~~~~~~~ @@ -432,3 +386,4 @@ attribute or method doesn't exist. If set to ``false`` these errors are ignored and the non-existing values are replaced by ``null``. .. _`the optimizer extension`: https://twig.symfony.com/doc/2.x/api.html#optimizer-extension +.. _`XSS attacks`: https://en.wikipedia.org/wiki/Cross-site_scripting diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 083583727e7..6725f9a7f46 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -1,38 +1,19 @@ .. index:: single: Symfony Twig extensions -.. _symfony2-twig-extensions: +Twig Extensions Defined by Symfony +================================== -Symfony Twig Extensions -======================= - -Twig is the default template engine for Symfony. By itself, it already contains -a lot of built-in functions, filters, tags and tests. You can learn more about -them from the `Twig Reference`_. - -The Symfony framework adds quite a few extra :ref:`functions `, -:ref:`filters `, :ref:`tags ` -and :ref:`tests ` to seamlessly integrate the -various Symfony components with Twig templates. The following sections -describe these extra features. - -.. tip:: - - Technically, most of the extensions live in the `Twig Bridge`_. That code - might give you some ideas when you need to write your own Twig extension - as described in :doc:`/templating/twig_extension`. - -.. note:: - - This reference only covers the Twig extensions provided by the Symfony - framework. You are probably using some other bundles as well, and - those might come with their own extensions not covered here. +:ref:`Twig ` is the template engine used in Symfony applications. +There are tens of `default filters and functions defined by Twig`_, but Symfony +also defines some filters, functions and tags to integrate the various Symfony +components with Twig templates. This article explains them all. .. tip:: - The `Twig Extensions repository`_ contains some additional Twig extensions - that do not belong to the Twig core, so you might want to have a look at - the `Twig Extensions documentation`_. + If these extensions provided by Symfony are not enough, you can + :doc:`create a custom Twig extension ` to define + even more filters and functions. .. _reference-twig-functions: @@ -54,20 +35,8 @@ render **type**: ``array`` **default**: ``[]`` Makes a request to the given internal URI or controller and returns the result. -It's commonly used to :doc:`embed controllers in templates `. - -.. code-block:: twig - - {# if the controller is associated with a route, use the path() or - url() functions to generate the URI used by render() #} - {{ render(path('latest_articles', {num: 5})) }} - {{ render(url('latest_articles', {num: 5})) }} - - {# if you don't want to expose the controller with a public URL, use - the controller() function to define the controller to be executed #} - {{ render(controller('App\\Controller\\DefaultController::latestArticles', {num: 5})) }} - The render strategy can be specified in the ``strategy`` key of the options. +It's commonly used to :ref:`embed controllers in templates `. .. _reference-twig-function-render-esi: @@ -112,6 +81,8 @@ Returns an instance of ``ControllerReference`` to be used with functions like :ref:`render() ` and :ref:`render_esi() `. +.. _reference-twig-function-asset: + asset ~~~~~ @@ -124,12 +95,18 @@ asset ``packageName`` *(optional)* **type**: ``string`` | ``null`` **default**: ``null`` -Returns a public path to ``path``, which takes into account the base path -set for the package and the URL path. More information in -:ref:`templating-assets`. Symfony provides various cache busting -implementations via the :ref:`reference-framework-assets-version`, -:ref:`reference-assets-version-strategy`, and -:ref:`reference-assets-json-manifest-path` configuration options. +Returns the public path of the given asset path (which can be a CSS file, a +JavaScript file, an image path, etc.). This function takes into account where +the application is installed (e.g. in case the project is accessed in a host +subirectory) and the optional asset package base path. + +Symfony provides various cache busting implementations via the +:ref:`reference-framework-assets-version`, :ref:`reference-assets-version-strategy`, +and :ref:`reference-assets-json-manifest-path` configuration options. + +.. seealso:: + + Read more about :ref:`linking to web assets from templates `. asset_version ~~~~~~~~~~~~~~ @@ -142,7 +119,7 @@ asset_version **type**: ``string`` | ``null`` **default**: ``null`` Returns the current version of the package, more information in -:ref:`templating-assets`. +:ref:`templates-link-to-assets`. .. _reference-twig-function-csrf-token: @@ -211,7 +188,7 @@ path .. code-block:: twig - {{ path(name, parameters = [], relative = false) }} + {{ path(route_name, route_parameters = [], relative = false) }} ``name`` **type**: ``string`` @@ -221,19 +198,19 @@ path **type**: ``boolean`` **default**: ``false`` Returns the relative URL (without the scheme and host) for the given route. -If ``relative`` is enabled, it'll create a path relative to the current -path. More information in :ref:`templating-pages`. +If ``relative`` is enabled, it'll create a path relative to the current path. .. seealso:: - Read :doc:`/routing` to learn more about the Routing component. + Read more about :doc:`Symfony routing ` and about + :ref:`creating links in Twig templates `. url ~~~ .. code-block:: twig - {{ url(name, parameters = [], schemeRelative = false) }} + {{ url(route_name, route_parameters = [], schemeRelative = false) }} ``name`` **type**: ``string`` @@ -243,12 +220,12 @@ url **type**: ``boolean`` **default**: ``false`` Returns the absolute URL (with scheme and host) for the given route. If -``schemeRelative`` is enabled, it'll create a scheme-relative URL. More -information in :ref:`templating-pages`. +``schemeRelative`` is enabled, it'll create a scheme-relative URL. .. seealso:: - Read :doc:`/routing` to learn more about the Routing component. + Read more about :doc:`Symfony routing ` and about + :ref:`creating links in Twig templates `. absolute_url ~~~~~~~~~~~~ @@ -260,17 +237,9 @@ absolute_url ``path`` **type**: ``string`` -Returns the absolute URL from the passed relative path. For example, assume -you're on the following page in your app: -``http://example.com/products/hover-board``. - -.. code-block:: twig - - {{ absolute_url('/human.txt') }} - {# http://example.com/human.txt #} - - {{ absolute_url('products_icon.png') }} - {# http://example.com/products/products_icon.png #} +Returns the absolute URL from the passed relative path. Combine it with the +:ref:`asset() function ` to generate absolute URLs +for web assets. Read more about :ref:`Linking to CSS, JavaScript and Image Assets `. relative_path ~~~~~~~~~~~~~ @@ -297,8 +266,8 @@ you're on the following page in your app: expression ~~~~~~~~~~ -Creates an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` in -Twig. +Creates an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` related +to the :doc:`ExpressionLanguage component `. Form Related Functions ~~~~~~~~~~~~~~~~~~~~~~ @@ -652,27 +621,11 @@ in the article about :doc:`customizing form rendering Global Variables ---------------- -.. _reference-twig-global-app: - app ~~~ -The ``app`` variable is available everywhere and gives access to many commonly -needed objects and values. It is an instance of -:class:`Symfony\\Bundle\\FrameworkBundle\\Templating\\GlobalVariables`. - -The available attributes are: - -* ``app.user``, a PHP object representing the current user; -* ``app.request``, a :class:`Symfony\\Component\\HttpFoundation\\Request` object; -* ``app.session``, a :class:`Symfony\\Component\\HttpFoundation\\Session\\Session` object; -* ``app.environment``, a string with the name of the execution environment; -* ``app.debug``, a boolean telling whether the debug mode is enabled in the app; -* ``app.token``, a :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface` - object representing the security token -* ``app.flashes``, returns flash messages from the session - -.. _`Twig Reference`: https://twig.symfony.com/doc/2.x/#reference -.. _`Twig Extensions repository`: https://github.com/twigphp/Twig-extensions -.. _`Twig Extensions documentation`: http://twig-extensions.readthedocs.io/en/latest/ -.. _`Twig Bridge`: https://github.com/symfony/symfony/tree/master/src/Symfony/Bridge/Twig/Extension +The ``app`` variable is injected automatically by Symfony in all templates and +provides access to lots of useful application information. Read more about the +:ref:`Twig global app variable `. + +.. _`default filters and functions defined by Twig`: https://twig.symfony.com/doc/2.x/#reference diff --git a/routing.rst b/routing.rst index ed74ae8239e..c883613afd6 100644 --- a/routing.rst +++ b/routing.rst @@ -1238,8 +1238,8 @@ information in a controller via the ``Request`` object:: You can get this information in services too injecting the ``request_stack`` service to :doc:`get the Request object in a service `. -In Twig templates, use the :ref:`global app object ` -to get the request and its attributes: +In templates, use the :ref:`Twig global app variable ` to get +the request and its attributes: .. code-block:: twig @@ -1256,67 +1256,14 @@ Symfony defines some special controllers to render templates and redirect to other routes from the route configuration so you don't have to create a controller action. -Rendering Templates -~~~~~~~~~~~~~~~~~~~ - -Use the ``TemplateController`` to render the template whose path is defined in -the ``template`` option: - -.. configuration-block:: - - .. code-block:: yaml - - # config/routes.yaml - about_us: - path: /site/about-us - controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction - defaults: - template: 'static_pages/about_us.html.twig' - - # optionally you can define some arguments passed to the template - site_name: 'ACME' - theme: 'dark' - - .. code-block:: xml - - - - +Rendering a Template Directly from a Route +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - static_pages/about_us.html.twig +Read the section about :ref:`rendering a template from a route ` +in the main article about Symfony templates. - - ACME - dark - - - - .. code-block:: php - - // config/routes.php - use App\Controller\DefaultController; - use Symfony\Bundle\FrameworkBundle\Controller\TemplateController; - use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; - - return function (RoutingConfigurator $routes) { - $routes->add('about_us', '/site/about-us') - ->controller([TemplateController::class, 'templateAction']) - ->defaults([ - 'template' => 'static_pages/about_us.html.twig', - // optionally you can define some arguments passed to the template - 'site_name' => 'ACME', - 'theme' => 'dark', - ]) - ; - }; - -Redirecting to URLs and Routes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Redirecting to URLs and Routes Directly from a Route +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the ``RedirectController`` to redirect to other routes (``redirectAction``) and URLs (``urlRedirectAction``): @@ -1901,28 +1848,8 @@ the :class:`Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface` class Generating URLs in Templates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The Twig template language used in :doc:`Symfony templates ` -provides some functions to generate both relative and absolute URLs: - -.. code-block:: html+twig - - {# generates relative URLs #} - Sign up - - View your profile - - - Ver mi perfil - - - {# generates absolute URLs #} - Sign up - - View your profile - - - Ver mi perfil - +Read the section about :ref:`creating links between pages ` +in the main article about Symfony templates. Generating URLs in JavaScript ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/security.rst b/security.rst index ad20d0df512..8d01e5273d9 100644 --- a/security.rst +++ b/security.rst @@ -723,8 +723,8 @@ If you need to get the logged in user from a service, use the Fetch the User in a Template ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In a Twig Template the user object can be accessed via the :ref:`app.user ` -key: +In a Twig Template the user object is available via the ``app.user`` variable +thanks to the :ref:`Twig global app variable `: .. code-block:: html+twig diff --git a/templates.rst b/templates.rst new file mode 100644 index 00000000000..610b2e163bb --- /dev/null +++ b/templates.rst @@ -0,0 +1,1100 @@ +.. index:: + single: Templating + +Creating and Using Templates +============================ + +A template is the best way to organize and render HTML from inside your application, +whether you need to render HTML from a :doc:`controller ` or generate +the :doc:`contents of an email `. Templates in Symfony are created with +Twig: a flexible, fast, and secure template engine. + +.. _twig-language: + +Twig Templating Language +------------------------ + +The `Twig`_ templating language allows you to write concise, readable templates +that are more friendly to web designers and, in several ways, more powerful than +PHP templates. Take a look at the following Twig template example. Even if it's +the first time you see Twig, you probably understand most of it: + +.. code-block:: html+twig + + + + + Welcome to Symfony! + + +

{{ page_title }}

+ + {% if user.isLoggedIn %} + Hello {{ user.name }}! + {% endif %} + + {# ... #} + + + +Twig syntax is based on these three constructs: + +* ``{{ ... }}``, used to display the content of a variable or the result of + evaluating an expression; +* ``{% ... %}``, used to run some logic, such as a conditional or a loop; +* ``{# ... #}``, used to add comments to the template (unlike HTML comments, + these comments are not included in the rendered page). + +You can't run PHP code inside Twig templates, but Twig provides utilities to +run some logic in the templates. For example, **filters** modify content before +being rendered, like the ``upper`` filter to uppercase contents: + +.. code-block:: twig + + {{ title|upper }} + +Twig comes with a long list of `tags`_, `filters`_ and `functions`_ that are +available by default. In Symfony applications you can also use these +:doc:`Twig filters and functions defined by Symfony ` +and you can :doc:`create your own Twig filters and functions `. + +Twig is fast in the ``prod`` :ref:`environment ` +(because templates are compiled into PHP and cached automatically), but +convenient to use in the ``dev`` environment (because templates are recompiled +automatically when you change them). + +Twig Configuration +~~~~~~~~~~~~~~~~~~ + +Twig has several configuration options to define things like the format used +to display numbers and dates, the template caching, etc. Read the +:doc:`Twig configuration reference ` to learn about them. + +Creating Templates +------------------ + +Before explaining in detail how to create and render templates, look at the +following example for a quick overview of the whole process. First, you need to +create a new file in the ``templates/`` directory to store the template contents: + +.. code-block:: html+twig + + {# templates/user/notifications.html.twig #} +

Hello {{ user_first_name }}!

+

You have {{ notifications|length }} new notifications.

+ +Then, create a :doc:`controller ` that renders this template and +passes to it the needed variables:: + + // src/Controller/UserController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + + class UserController extends AbstractController + { + // ... + + public function notifications() + { + // get the user information and notifications somehow + $userFirstName = '...'; + $userNotifications = ['...', '...']; + + // the template path is the relative file path from `templates/` + return $this->render('user/notifications.html.twig', [ + // this array defines the variables passed to the template, + // where the key is the variable name and the value is the variable value + // (Twig recommends using snake_case variable names: 'foo_bar' instead of 'fooBar') + 'user_first_name' => $userFirstName, + 'notifications' => $userNotifications, + ]); + } + } + +Template Naming +~~~~~~~~~~~~~~~ + +Symfony recommends the following for template names: + +* Use `snake case`_ for filenames and directories (e.g. ``blog_posts.twig``, + ``admin/default_theme/blog/index.twig``, etc.); +* Define two extensions for filenames (e.g. ``index.html.twig`` or + ``blog_posts.xml.twig``) being the first extension (``html``, ``xml``, etc.) + the final format that the template will generate. + +Although templates usually generate HTML contents, they can generate any +text-based format. That's why the two-extension convention simplifies the way +templates are created and rendered for multiple formats. + +Template Location +~~~~~~~~~~~~~~~~~ + +Templates are stored by default in the ``templates/`` directory. When a service +or controller renders the ``product/index.html.twig`` template, they are actually +referring to the ``/templates/product/index.html.twig`` file. + +The default templates directory is configurable with the +:ref:`twig.default_path ` option and you can add more +template directories :ref:`as explained later ` in this article. + +Template Variables +~~~~~~~~~~~~~~~~~~ + +A common need for templates is to print the values stored in the templates +passed from the controller or service. Variables usually store objects and +arrays instead of strings, numbers and boolean values. That's why Twig provides +quick access to complex PHP variables. Consider the following template: + +.. code-block:: html+twig + +

{{ user.name }} added this comment on {{ comment.publishedAt|date }}

+ +The ``user.name`` notation means that you want to display some information +(``name``) stored in a variable (``user``). Is ``user`` an array or an object? +Is ``name`` a property or a method? In Twig this doesn't matter. + +When using the ``foo.bar`` notation, Twig tries to get the value of the variable +in the following order: + +#. ``$foo['bar']`` (array and element); +#. ``$foo->bar`` (object and public property); +#. ``$foo->bar()`` (object and public method); +#. ``$foo->getBar()`` (object and *getter* method); +#. ``$foo->isBar()`` (object and *isser* method); +#. ``$foo->hasBar()`` (object and *hasser* method); +#. If none of the above exists, use ``null``. + +This allows to evolve your application code without having to change the +template code (you can start with array variables for the application proof of +concept, then move to objects with methods, etc.) + +.. _templates-link-to-pages: + +Linking to Pages +~~~~~~~~~~~~~~~~ + +Instead of writing the link URLs by hand, use the ``path()`` function to +generate URLs based on the :ref:`routing configuration `. + +Later, if you want to modify the URL of a particular page, all you'll need to do +is change the routing configuration: the templates will automatically generate +the new URL. + +Consider the following routing configuration: + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Controller/BlogController.php + + // ... + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController + { + /** + * @Route("/", name="blog_index") + */ + public function index() + { + // ... + } + + /** + * @Route("/article/{slug}", name="blog_post") + */ + public function show(string $slug) + { + // ... + } + } + + .. code-block:: yaml + + # config/routes.yaml + blog_index: + path: / + controller: App\Controller\BlogController::index + + blog_post: + path: /article/{slug} + controller: App\Controller\BlogController::show + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/routes.php + use App\Controller\BlogController; + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + + return function (RoutingConfigurator $routes) { + $routes->add('blog_index', '/') + ->controller([BlogController::class, 'index']) + ; + + $routes->add('blog_post', '/articles/{slug}') + ->controller([BlogController::class, 'show']) + ; + }; + +Use the ``path()`` Twig function to link to these pages and pass the route name +as the first argument and the route parameters as the optional second argument: + +.. code-block:: html+twig + + Homepage + + {# ... #} + + {% for post in blog_posts %} +

+ {{ post.title }} +

+ +

{{ post.excerpt }}

+ {% endfor %} + +The ``path()`` function generates relative URLs. If you need to generate +absolute URLs (for example when rendering templates for emails or RSS feeds), +use the ``url()`` function, which takes the same arguments as ``path()`` +(e.g. `` ... ``). + +.. _templates-link-to-assets: + +Linking to CSS, JavaScript and Image Assets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a template needs to link to a static asset (e.g. an image), Symfony provides +an ``asset()`` Twig function to help generate that URL. First, install the +``asset`` package: + +.. code-block:: terminal + + $ composer require symfony/asset + +You can now use the ``asset()`` function: + +.. code-block:: html+twig + + {# the image lives at "public/images/logo.png" #} + Symfony! + + {# the CSS file lives at "public/css/blog.css" #} + + + {# the JS file lives at "public/bundles/acme/js/loader.js" #} + + +The ``asset()`` function's main purpose is to make your application more portable. +If your application lives at the root of your host (e.g. ``https://example.com``), +then the rendered path should be ``/images/logo.png``. But if your application +lives in a subdirectory (e.g. ``https://example.com/my_app``), each asset path +should render with the subdirectory (e.g. ``/my_app/images/logo.png``). The +``asset()`` function takes care of this by determining how your application is +being used and generating the correct paths accordingly. + +.. tip:: + + The ``asset()`` function supports various cache busting techniques via the + :ref:`version `, + :ref:`version_format `, and + :ref:`json_manifest_path ` configuration options. + +.. tip:: + + If you'd like help packaging, versioning and minifying your JavaScript and + CSS assets in a modern way, read about :doc:`Symfony's Webpack Encore `. + +If you need absolute URLs for assets, use the ``absolute_url()`` Twig function +as follows: + +.. code-block:: html+twig + + Symfony! + + + +.. _twig-app-variable: + +The App Global Variable +~~~~~~~~~~~~~~~~~~~~~~~ + +Symfony creates a context object that is injected into every Twig template +automatically as a variable called ``app``. It provides access to some +application information: + +.. code-block:: html+twig + +

Username: {{ app.user.username ?? 'Anonymous user' }}

+ {% if app.debug %} +

Request method: {{ app.request.method }}

+

Application Environment: {{ app.environment }}

+ {% endif %} + +The ``app`` variable (which is an instance of :class:`Symfony\\Bridge\\Twig\\AppVariable`) +gives you access to these variables: + +``app.user`` + The :ref:`current user object ` or ``null`` if the user + is not authenticated. +``app.request`` + The :class:`Symfony\\Component\\HttpFoundation\\Request` object that stores + the current :ref:`request data ` (depending on your + application, this can be a :ref:`sub-request ` + or a regular request). +``app.session`` + The :class:`Symfony\\Component\\HttpFoundation\\Session\\Session` object that + represents the current :doc:`user's session ` or ``null`` if there is none. +``app.flashes`` + An array of all the :ref:`flash messages ` stored in the session. + You can also get only the messages of some type (e.g. ``app.flashes('notice')``). +``app.environment`` + The name of the current :ref:`configuration environment ` + (``dev``, ``prod``, etc). +``app.debug`` + True if in :ref:`debug mode `. False otherwise. +``app.token`` + A :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface` + object representing the security token. + +In addition to the global ``app`` variable injected by Symfony, you can also +:doc:`inject variables automatically to all Twig templates `. + +.. _templates-rendering: + +Rendering Templates +------------------- + +Rendering a Template in Controllers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your controller extends from the :ref:`AbstractController `, +use the ``render()`` helper:: + + // src/Controller/ProductController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + + class ProductController extends AbstractController + { + public function index() + { + // ... + + return $this->render('product/index.html.twig', [ + 'category' => '...', + 'promotions' => ['...', '...'], + ]); + } + } + +If your controller does not extend from ``AbstractController``, you'll need to +:ref:`fetch services in your controller ` and +use the ``render()`` method of the ``twig`` service. + +Rendering a Template in Services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Inject the ``twig`` Symfony service into your own services and use its +``render()`` method. When using :doc:`service autowiring ` +you only need to add an argument in the service constructor and type-hint it with +the :class:`Twig\\Environment` class:: + + // src/Service/SomeService.php + use Twig\Environment; + + class SomeService + { + private $twig; + + public function __construct(Environment $twig) + { + $this->twig = $twig; + } + + public function someMethod() + { + // ... + + $htmlContents = $this->twig->render('product/index.html.twig', [ + 'category' => '...', + 'promotions' => ['...', '...'], + ]); + } + } + +Rendering a Template in Emails +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Read the docs about the :ref:`mailer and Twig integration `. + +.. _templates-render-from-route: + +Rendering a Template Directly from a Route +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Although templates are usually rendered in controllers and services, you can +render static pages that don't need any variables directly from the route +definition. Use the special ``TemplateController`` provided by Symfony:: + +.. configuration-block:: + + .. code-block:: yaml + + # config/routes.yaml + acme_privacy: + path: /privacy + controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController + defaults: + # the path of the template to render + template: 'static/privacy.html.twig' + + # special options defined by Symfony to set the page cache + maxAge: 86400 + sharedAge: 86400 + + # optionally you can define some arguments passed to the template + site_name: 'ACME' + theme: 'dark' + + .. code-block:: xml + + + + + + + + static/privacy.html.twig + + + 86400 + 86400 + + + ACME + dark + + + + .. code-block:: php + + // config/routes.php + use Symfony\Bundle\FrameworkBundle\Controller\TemplateController; + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + + return function (RoutingConfigurator $routes) { + $routes->add('acme_privacy', '/privacy') + ->controller(TemplateController::class) + ->defaults([ + // the path of the template to render + 'template' => 'static/privacy.html.twig', + + // special options defined by Symfony to set the page cache + 'maxAge' => 86400, + 'sharedAge' => 86400, + + // optionally you can define some arguments passed to the template + 'site_name' => 'ACME', + 'theme' => 'dark', + ]) + ; + }; + +Checking if a Template Exists +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Templates are loaded in the application using a `Twig template loader`_, which +also provides a method to check for template existence. First, get the loader:: + + // in a controller extending from AbstractController + $loader = $this->get('twig')->getLoader(); + + // in a service using autowiring + use Twig\Environment; + + public function __construct(Environment $twig) + { + $loader = $twig->getLoader(); + } + +Then, pass the path of the Twig template to the ``exists()`` method of the loader:: + + if ($loader->exists('theme/layout_responsive.html.twig')) { + // the template exists, do something + // ... + } + +Debugging Templates +------------------- + +Symfony provides several utilities to help you debug issues in your templates. + +Linting Twig Templates +~~~~~~~~~~~~~~~~~~~~~~ + +The ``lint:twig`` command checks that your Twig templates don't have any syntax +errors. It's useful to run it before deploying your application to production +(e.g. in your continuous integration server): + +.. code-block:: terminal + + # check all the templates stored in a directory + $ php bin/console lint:twig templates/ + + # you can also check individual templates + $ php bin/console lint:twig templates/article/recent_list.html.twig + +Inspecting Twig Information +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``debug:twig`` command lists all the information available about Twig +(functions, filters, global variables, etc.). It's useful to check if your +:doc:`custom Twig extensions ` are working properly +and also to check the Twig features added when :ref:`installing packages `: + +.. code-block:: terminal + + # list general information + $ php bin/console debug:twig + + # filter output by any keyword + $ php bin/console debug:twig --filter=date + + # pass a template path to show the physical file which will be loaded + $ php bin/console debug:twig @Twig/Exception/error.html.twig + +The Dump Twig Utilities +~~~~~~~~~~~~~~~~~~~~~~~ + +Symfony provides a :ref:`dump() function ` as an +improved alternative to PHP's ``var_dump()`` function. This function is useful +to inspect the contents of any variable and you can use it in Twig templates too. + +First, make sure that the VarDumper component is installed in the application:: + +.. code-block:: terminal + + $ composer require symfony/var-dumper + +Then, use either the ``{% dump %}`` tag or the ``{{ dump() }}`` function +depending on your needs: + +.. code-block:: html+twig + + {# templates/article/recent_list.html.twig #} + {# the contents of this variable are sent to the Web Debug Toolbar + instead of dumping them inside the page contents #} + {% dump articles %} + + {% for article in articles %} + {# the contents of this variable are dumped inside the page contents + and they are visible on the web page #} + {{ dump(article) }} + + + {{ article.title }} + + {% endfor %} + +To avoid leaking sensitive information, the ``dump()`` function/tag is only +available in the ``dev`` and ``test`` :ref:`configuration environments `. +If you try to use it in the ``prod`` environment, you will see a PHP error. + +Reusing Template Contents +------------------------- + +.. _templates-include: + +Including Templates +~~~~~~~~~~~~~~~~~~~ + +If certain Twig code is repeated in several templates, you can extract it into a +single "template fragment" and include it in other templates. Imagine that the +following code to display the user information is repeated in several places: + +.. code-block:: html+twig + + {# templates/blog/index.html.twig #} + + {# ... #} + + +First, create a new Twig template called ``blog/_user_profile.html.twig`` (the +``_`` prefix is optional, but it's a convention used to better differentiate +between full templates and template fragments). + +Then, remove that content from the original ``blog/index.html.twig`` template +and add the following to include the template fragment: + +.. code-block:: twig + + {# templates/blog/index.html.twig #} + + {# ... #} + {{ include('blog/_user_profile.html.twig') }} + +The ``include()`` Twig function takes as argument the path of the template to +include. The included template has access to all the variables of the template +that includes it (use the `with_context`_ option to control this). + +You can also pass variables to the included template. This is useful for example +to rename variables. Imagine that your template stores the user information in a +variable called ``blog_post.author`` instead of the ``user`` variable that the +template fragment expects. Use the following to *rename* the variable: + +.. code-block:: twig + + {# templates/blog/index.html.twig #} + + {# ... #} + {{ include('blog/_user_profile.html.twig', {user: blog_post.author}) }} + +.. _templates-embed-controllers: + +Embedding Controllers +~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Including template fragments ` is useful to reuse the +same content on several pages. However, this technique is not the best solution +in some cases. + +Imagine that the template fragment displays the three most recent blog articles. +To do that, it needs to make a database query to get those articles. When using +the ``include()`` function, you'd need to do the same database query in every +page that includes the fragment. This is not very convenient. + +A better alternative is to **embed the result of executing some controller** +with the ``render()`` and ``controller()`` Twig functions. + +First, create the controller that renders a certain number of recent articles:: + + // src/Controller/BlogController.php + namespace App\Controller; + + // ... + + class BlogController extends AbstractController + { + public function recentArticles($max = 3) + { + // get the recent articles somehow (e.g. making a database query) + $articles = ['...', '...', '...']; + + return $this->render('blog/_recent_articles.html.twig', [ + 'articles' => $articles + ]); + } + } + +Then, create the ``blog/_recent_articles.html.twig`` template fragment (the +``_`` prefix in the template name is optional, but it's a convention used to +better differentiate between full templates and template fragments): + +.. code-block:: html+twig + + {# templates/blog/_recent_articles.html.twig #} + {% for article in articles %} + + {{ article.title }} + + {% endfor %} + +Now you can call to this controller from any template to embed its result: + +.. code-block:: html+twig + + {# templates/base.html.twig #} + + {# ... #} + + +.. _fragments-path-config: + +When using the ``controller()`` function, controllers are not accessed using a +regular Symfony route but through a special URL used exclusively to serve those +template fragments. Configure that special URL in the ``fragments`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + fragments: { path: /_fragment } + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // config/packages/framework.php + $container->loadFromExtension('framework', [ + // ... + 'fragments' => ['path' => '/_fragment'], + ]); + +.. caution:: + + Embedding controllers require making requests to those controllers and + rendering some templates as result. This can have a significant impact in + the application performance if you embed lots of controllers. If possible, + :doc:`cache the template fragment `. + +.. seealso:: + + Templates can also :doc:`embed contents asynchronously ` + with the ``hinclude.js`` JavaScript library. + +Template Inheritance and Layouts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As your application grows you'll find more and more repeated elements between +pages, such as headers, footers, sidebars, etc. :ref:`Including templates ` +and :ref:`embedding controllers ` can help, but +when pages share a common structure, it's better to use **inheritance**. + +The concept of `Twig template inheritance`_ is similar to PHP class inheritance. +You define a parent template that other templates can extend from and child +templates can override parts of the parent template. + +Symfony recommends the following three-level template inheritance for medium and +complex applications: + +* ``templates/base.html.twig``, defines the common elements of all application + templates, such as ````, ``
``, ``