diff --git a/book/templating.rst b/book/templating.rst index 4d99b4dc9bc..58aa675b5ee 100644 --- a/book/templating.rst +++ b/book/templating.rst @@ -8,22 +8,24 @@ As you know, the :doc:`controller ` is responsible for handling each request that comes into a Symfony application. In reality, the controller delegates most of the heavy work to other places so that code can be tested and reused. When a controller needs to generate HTML, -CSS or any other content, it hands the work off to the templating engine. +CSS or any other content, it hands the work off to the **templating engine**. In this chapter, you'll learn how to write powerful templates that can be used to return content to the user, populate email bodies, and more. You'll learn shortcuts, clever ways to extend templates and how to reuse template code. -.. note:: +.. seealso:: How to render templates is covered in the - :ref:`controller ` page of the book. + :ref:`Controller chapter ` of the book. .. index:: single: Templating; What is a template? + single: Templating; PHP templating engine + single: Templating; Twig templating engine -Templates ---------- +PHP versus Twig +--------------- A template is simply a text file that can generate any text-based format (HTML, XML, CSV, LaTeX ...). The most familiar type of template is a *PHP* @@ -51,8 +53,6 @@ template - a text file parsed by PHP that contains a mix of text and PHP code: -.. index:: Twig; Introduction - But Symfony packages an even more powerful templating language called `Twig`_. Twig allows you to write concise, readable templates that are more friendly to web designers and, in several ways, more powerful than PHP templates: @@ -75,6 +75,202 @@ to web designers and, in several ways, more powerful than PHP templates: +Throughout this chapter, template examples will be shown in both Twig and PHP. + +.. note:: + + The Twig engine is mandatory to use the ``web_profiler`` (as well as + many third-party bundles). + +.. note:: + + If you *do* choose to not use Twig and you disable it, you'll need it + implement your own exception handler via the ``kernel.exception`` event. + See cookbook article :doc:`/cookbook/templating/PHP`. + +.. index:: + single: Templating; Template formats + single: Templating; Rendering different template formats + +.. _template-formats: + +Template Suffix +--------------- + +Every template name also has two extensions that specify the *format* and +*engine* for that template. Templates are a generic way to render content in +*any* format. And while in most cases you'll use templates to render HTML +content, a template can just as easily generate JavaScript, CSS, XML or any +other format you can dream of. + +======================== ====== ====== +Filename Format Engine +======================== ====== ====== +``blog/index.html.twig`` HTML Twig +``blog/index.html.php`` HTML PHP +``blog/index.css.twig`` CSS Twig +======================== ====== ====== + +By default, any Symfony template can be written in either Twig or PHP, and +the last part of the extension (e.g. ``.twig`` or ``.php``) specifies which +of these two *engines* should be used. The first part of the extension, +(e.g. ``.html``, ``.css``, etc) is the final format that the template will +generate. In reality, this is nothing more than a naming convention and the +template isn't actually rendered differently based on its format. + +.. seealso:: + + How to render templates is covered in the + :ref:`Controller chapter ` of the book. + +In many cases, you may want to allow a single controller to render multiple +different formats based on the "request format". For that reason, a common +pattern is to do the following:: + + public function indexAction(Request $request) + { + $format = $request->getRequestFormat(); + + return $this->render('article/index.'.$format.'.twig'); + } + +The ``getRequestFormat()`` method on the ``Request`` object defaults to ``html``, +but can return any other format based on the format requested by the user. +The request format is most often managed by the routing, where a route can +be configured so that ``/contact`` sets the request format to ``html`` while +``/contact.xml`` sets the format to ``xml``. For more information, see the +:ref:`Advanced Routing Example ` section in the +Routing chapter. + +.. index:: + single: Templating; The templating service + +.. _book-templating-engine: + +Configuring and Using the ``templating`` Service +------------------------------------------------ + +The heart of the template system in Symfony is the ``templating`` engine. +This special object is responsible for rendering templates (determines how +Symfony parses the template) and returning their content. When you render a +template in a controller, for example, you're actually using the +``templating`` engine service. For example:: + + return $this->render('article/index.html.twig'); + +is equivalent to:: + + use Symfony\Component\HttpFoundation\Response; + + $engine = $this->container->get('templating'); + $content = $engine->render('article/index.html.twig'); + + return $response = new Response($content); + +.. _template-configuration: + +The templating engine (or "service") is preconfigured to work automatically +inside Symfony. It can, of course, be configured further in the default +application configuration file:: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + # ... + templating: { engines: ['twig'] } + + .. code-block:: xml + + + + + + + + + twig + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + // ... + + 'templating' => array( + 'engines' => array('twig'), + ), + )); + +Several configuration options are available and are covered in the reference +section of the doc inside :doc:`/reference/configuration/framework`. + +.. index:: + single: Templating; Global template variables + +Global Template Variables +------------------------- + +During each request, Symfony will set a global template variable ``app`` +in both Twig and PHP template engines by default. The ``app`` variable +is a :class:`Symfony\\Bundle\\FrameworkBundle\\Templating\\GlobalVariables` +instance which will give you access to some application specific variables +automatically: + +``app.security`` + The security context. +``app.user`` + The current user object. +``app.request`` + The request object. +``app.session`` + The session object. +``app.environment`` + The current environment (``dev``, ``prod``, etc.). +``app.debug`` + ``true`` if in debug mode, ``false`` otherwise. + +Practical example:: + +.. configuration-block:: + + .. code-block:: html+twig + +

Username: {{ app.user.username }}

+ {% if app.debug %} +

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

+

Application Environment: {{ app.environment }}

+ {% endif %} + + .. code-block:: html+php + +

Username: getUser()->getUsername() ?>

+ getDebug()): ?> +

Request method: getRequest()->getMethod() ?>

+

Application Environment: getEnvironment() ?>

+ + +.. tip:: + + You can add your own global template variables. See the cookbook article + :doc:`Global Variables `. + +.. index:: + single: Twig; Introduction + single: Twig; Twig syntax + +Twig Syntax +----------- + Twig defines three types of special syntax: ``{{ ... }}`` @@ -82,34 +278,49 @@ Twig defines three types of special syntax: template. ``{% ... %}`` - "Does something": a **tag** that controls the logic of the template; it is - used to execute statements such as for-loops for example. + "Does something": a **tag** that controls the logic of the template; it + is used to execute flow-control statements such as for-loops for example. ``{# ... #}`` - "Comment something": it's the equivalent of the PHP ``/* comment */`` syntax. - It's used to add single or multi-line comments. The content of the comments - isn't included in the rendered pages. + "Comment something": it's the equivalent of the PHP ``/* comment */`` + syntax. It's used to add single or multi-line comments. The content of + the comments isn't included in the rendered pages. + +.. seealso:: + + Twig official documentation is available `here`_. Twig also contains **filters**, which modify content before being rendered. The following makes the ``title`` variable all uppercase before rendering -it: +it:: -.. code-block:: twig +.. code-block:: html+twig {{ title|upper }} -Twig comes with a long list of `tags`_ and `filters`_ that are available -by default. You can even `add your own extensions`_ to Twig as needed. +Twig Extensions +~~~~~~~~~~~~~~~ -.. tip:: +`Twig extensions`_ are packages that add new features to Twig. Twig comes with +several types of extensions: - Registering a Twig extension is as easy as creating a new service and tagging - it with ``twig.extension`` :ref:`tag `. +* ``Twig_Extension_Core`` +* ``Twig_Extension_Escaper`` +* ``Twig_Extension_Sandbox`` +* ``Twig_Extension_Profiler`` +* ``Twig_Extension_Optimizer`` -As you'll see throughout the documentation, Twig also supports functions -and new functions can be easily added. For example, the following uses a -standard ``for`` tag and the ``cycle`` function to print ten div tags, with -alternating ``odd``, ``even`` classes: +``core`` extension defines all the core features of Twig. There are four +``core`` extensions - we have already seen two:: + +* `functions`_: Content generation +* `filters`_: Value transformation +* `tags`_: DSL language construct +* `tests`_: Boolean decision + +For example, the following uses a standard ``for`` tag and the ``cycle()`` +function to print ten HTML ``
`` tags, with alternating ``odd``, ``even`` +classes: .. code-block:: html+twig @@ -119,40 +330,42 @@ alternating ``odd``, ``even`` classes:
{% endfor %} -Throughout this chapter, template examples will be shown in both Twig and PHP. - -.. tip:: +You can `add your own extensions`_ to Twig as needed. Registering a +Twig extension is as easy as creating a new service and tagging it with +``twig.extension`` :ref:`tag `. - If you *do* choose to not use Twig and you disable it, you'll need to implement - your own exception handler via the ``kernel.exception`` event. +.. index:: + single: Twig; Why Twig? -.. sidebar:: Why Twig? +Why Twig? +~~~~~~~~~ - Twig templates are meant to be simple and won't process PHP tags. This - is by design: the Twig template system is meant to express presentation, - not program logic. The more you use Twig, the more you'll appreciate - and benefit from this distinction. And of course, you'll be loved by - web designers everywhere. +Twig templates are meant to be simple and won't process PHP tags. This +is by design: **the Twig template system is meant to express presentation, +not program logic**. The more you use Twig, the more you'll appreciate +and benefit from this distinction. And of course, you'll be loved by +web designers everywhere. - Twig can also do things that PHP can't, such as whitespace control, - sandboxing, automatic HTML escaping, manual contextual output escaping, - and the inclusion of custom functions and filters that only affect templates. - Twig contains little features that make writing templates easier and more concise. - Take the following example, which combines a loop with a logical ``if`` - statement: +Twig can also do things that PHP can't, such as whitespace control, +sandboxing, automatic HTML escaping, manual contextual output escaping, +and the inclusion of custom functions and filters that only affect templates. +Twig contains little features that make writing templates easier and more +concise. Take the following example, which combines a loop with a logical +``if`` statement: - .. code-block:: html+twig +.. code-block:: html+twig -
    - {% for user in users if user.active %} -
  • {{ user.username }}
  • - {% else %} -
  • No users found
  • - {% endfor %} -
+
    + {% for user in users if user.active %} +
  • {{ user.username }}
  • + {% else %} +
  • No users found
  • + {% endfor %} +
.. index:: - pair: Twig; Cache + single: Twig; Caching + single: Template; Caching Twig Template Caching ~~~~~~~~~~~~~~~~~~~~~ @@ -161,8 +374,8 @@ Twig is fast. Each Twig template is compiled down to a native PHP class that is rendered at runtime. The compiled classes are located in the ``app/cache/{environment}/twig`` directory (where ``{environment}`` is the environment, such as ``dev`` or ``prod``) and in some cases can be useful -while debugging. See :ref:`environments-summary` for more information on -environments. +while debugging. See :ref:`environments-summary` section for more information +on environments. When ``debug`` mode is enabled (common in the ``dev`` environment), a Twig template will be automatically recompiled when changes are made to it. This @@ -172,16 +385,27 @@ cache. When ``debug`` mode is disabled (common in the ``prod`` environment), however, you must clear the Twig cache directory so that the Twig templates will -regenerate. Remember to do this when deploying your application. +regenerate. Remember to do this when deploying your application. You can do +that by using ``cache:clear`` Console command:: + +.. code-block:: bash + + $ php app/console cache:clear --env=prod --no-debug .. index:: - single: Templating; Inheritance + single: Templating; Twig and PHP Inheritance + single: Twig; Inheritance .. _twig-inheritance: Template Inheritance and Layouts -------------------------------- +.. note:: + + Though the discussion about template inheritance will be in terms of Twig, + the philosophy is the same between Twig and PHP templates. + More often than not, templates in a project share common elements, like the header, footer, sidebar or more. In Symfony, this problem is thought about differently: a template can be decorated by another one. This works @@ -191,7 +415,7 @@ defined as **blocks** (think "PHP class with base methods"). A child template can extend the base layout and override any of its blocks (think "PHP subclass that overrides certain methods of its parent class"). -First, build a base layout file: +First, build a base layout file:: .. configuration-block:: @@ -227,7 +451,9 @@ First, build a base layout file: - <?php $view['slots']->output('title', 'Test Application') ?> + + <?php $view['slots']->output('title', 'Test Application') ?> + -Whenever you find that you need a variable or a piece of information that -you don't have access to in a template, consider rendering a controller. -Controllers are fast to execute and promote good code organization and reuse. -Of course, like all controllers, they should ideally be "skinny", meaning -that as much code as possible lives in reusable :doc:`services `. - -.. _book-templating-hinclude: - -Asynchronous Content with hinclude.js -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. versionadded:: 2.1 - hinclude.js support was introduced in Symfony 2.1 - -Controllers can be embedded asynchronously using the hinclude.js_ JavaScript library. -As the embedded content comes from another page (or controller for that matter), -Symfony uses a version of the standard ``render`` function to configure ``hinclude`` -tags: - -.. configuration-block:: - - .. code-block:: twig - - {{ render_hinclude(controller('...')) }} - {{ render_hinclude(url('...')) }} - - .. code-block:: php - - render( - new ControllerReference('...'), - array('renderer' => 'hinclude') - ) ?> - - render( - $view['router']->generate('...'), - array('renderer' => 'hinclude') - ) ?> - -.. note:: - - hinclude.js_ needs to be included in your page to work. +To refer to a controller the *logical controller name* is used (i.e. +**bundle**:**controller**:**action**). .. note:: - When using a controller instead of a URL, you must enable the Symfony - ``fragments`` configuration: + When embedding a result from a controller instead of some other page (a URL), + you must enable the Symfony `fragments`` configuration inside Symfony + default configuration file:: .. configuration-block:: @@ -764,8 +1141,52 @@ tags: 'fragments' => array('path' => '/_fragment'), )); -Default content (while loading or if JavaScript is disabled) can be set globally -in your application configuration: +.. index:: + single: Templating; Asynchronously Embedding Controllers + +.. _book-templating-hinclude: + +Asynchronously Embedding Controllers with hinclude.js +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.1 + hinclude.js support was introduced in Symfony 2.1 + +Controllers can be embedded asynchronously using the `hinclude.js`_ JavaScript +library. As the embedded content comes from another page (or controller for +that matter), Symfony uses a version of the standard Twig ``render()`` function +called ``render_hinclude()`` to configure ``hinclude`` tags:: + +.. configuration-block:: + + .. code-block:: twig + + {{ render_hinclude(controller('...')) }} + {{ render_hinclude(url('...')) }} + + .. code-block:: php + + render( + new ControllerReference('...'), + array('renderer' => 'hinclude') + ) ?> + + render( + $view['router']->generate('...'), + array('renderer' => 'hinclude') + ) ?> + +.. note:: + + `hinclude.js`_ needs to be included in your page to work. + +.. versionadded:: 2.2 + Default templates per ``render_hinclude()`` function was introduced in + Symfony 2.2. + +Default templates for ``render_hinclude()`` function (while loading or if +JavaScript is disabled) can be set globally in application default +configuration file:: .. configuration-block:: @@ -805,11 +1226,7 @@ in your application configuration: ), )); -.. versionadded:: 2.2 - Default templates per render function was introduced in Symfony 2.2 - -You can define default templates per ``render`` function (which will override -any global default template that is defined): +Of course global default template can be overridden:: .. configuration-block:: @@ -829,7 +1246,7 @@ any global default template that is defined): ) ) ?> -Or you can also specify a string to display as the default content: +You can also specify a string to display as the default content:: .. configuration-block:: @@ -848,22 +1265,29 @@ Or you can also specify a string to display as the default content: ) ?> .. index:: - single: Templating; Linking to pages + single: Templating; Genrating URLs inside templates .. _book-templating-pages: Linking to Pages ~~~~~~~~~~~~~~~~ -Creating links to other pages in your application is one of the most common -jobs for a template. Instead of hardcoding URLs in templates, use the ``path`` -Twig function (or the ``router`` helper in PHP) to generate URLs based on -the 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. +We will look at Twig ``path()`` and ``url()`` functions and PHP ``generate()`` +helper function. + +The most common place to generate a URL is from within a template when +linking between pages in an application. Instead of hardcoding URLs in +templates we just need to specify a route name. Later, if we want to +modify the URL of a particular page, all we'll need to do is change the +routing configuration; the templates will automatically generate the new URL. + +We can generate two types od URL: -First, link to the "_welcome" page, which is accessible via the following routing -configuration: +* relative URLs using ``path()`` function +* absolute URLs using ``url()`` function + +First, we will look at relative URLs. Create a route named "_welcome" and +associate it with a controller:: .. configuration-block:: @@ -919,20 +1343,25 @@ configuration: return $collection; -To link to the page, just use the ``path`` Twig function and refer to the route: +Now, inside Twig template link to the page, by using the ``path()`` Twig function +and refer to the route:: .. configuration-block:: .. code-block:: html+twig - Home + + Welcome! + .. code-block:: html+php - Home + + Welcome! + As expected, this will generate the URL ``/``. Now, for a more complicated -route: +route:: .. configuration-block:: @@ -989,9 +1418,13 @@ route: return $collection; In this case, you need to specify both the route name (``article_show``) and -a value for the ``{slug}`` parameter. Using this route, revisit the -``recent_list`` template from the previous section and link to the articles -correctly: +a value for the ``{slug}`` parameter. This is done using **hash maps** +(i.e.an array with named keys) as second attribute to the ``path()`` function. + +Here we will revisit the ``recent_list.html.twig`` template from the +:ref:`embedded controllers ` section where we +hard-coded the articles URL and correct this bad practice by linking to the +articles correctly:: .. configuration-block:: @@ -1015,16 +1448,17 @@ correctly: -.. tip:: - You can also generate an absolute URL by using the ``url`` Twig function: +Now, we will look at absolute URLs. Absolute URLs are generated using Twig +``url()`` function:: - .. code-block:: html+twig +.. configuration-block:: - Home + .. code-block:: html+twig - The same can be done in PHP templates by passing a third argument to - the ``generate()`` method: + + Read this blog post. + .. code-block:: html+php @@ -1032,11 +1466,39 @@ correctly: use Symfony\Component\Routing\Generator\UrlGeneratorInterface; ?> - Home + + Read this blog post. + + +Linking to Pages of Different Formats +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create links that include the special routing ``_format` parameter, +include a ``_format`` key in the parameter hash:: + +.. configuration-block:: + + .. code-block:: html+twig + + + PDF Version + + + .. code-block:: html+php + + + PDF Version + + +.. seealso:: + + To learn about special routing parameters like `_format` read + :ref:`section ` od the Routing chapter. .. index:: single: Templating; Linking to assets @@ -1047,8 +1509,9 @@ Linking to Assets ~~~~~~~~~~~~~~~~~ Templates also commonly refer to images, JavaScript, stylesheets and other -assets. Of course you could hard-code the path to these assets (e.g. ``/images/logo.png``), -but Symfony provides a more dynamic option via the ``asset`` Twig function: +assets. Of course you could hard-code the path to these assets (e.g. +``/images/logo.png``), but Symfony provides a more dynamic option via the +``asset()`` Twig function:: .. configuration-block:: @@ -1064,19 +1527,19 @@ but Symfony provides a more dynamic option via the ``asset`` Twig function: -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. ``http://example.com``), -then the rendered paths should be ``/images/logo.png``. But if your application +The ``asset()`` function's main purpose is to make application more portable. +If application lives at the root of the host (e.g. ``http://example.com``), +then the rendered paths should be ``/images/logo.png``. But if application lives in a subdirectory (e.g. ``http://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 +``asset()`` function takes care of this by determining how application is being used and generating the correct paths accordingly. -Additionally, if you use the ``asset`` function, Symfony can automatically +Additionally, if you use the ``asset()`` function, Symfony can automatically append a query string to your asset, in order to guarantee that updated static -assets won't be loaded from cache after being deployed. For example, ``/images/logo.png`` might -look like ``/images/logo.png?v2``. For more information, see the :ref:`reference-framework-assets-version` -configuration option. +assets won't be cached when deployed. For example, ``/images/logo.png`` might +look like ``/images/logo.png?v2``. For more information, see the +:ref:`reference-framework-assets-version` configuration option. .. index:: single: Templating; Including stylesheets and JavaScripts @@ -1084,7 +1547,7 @@ configuration option. single: JavaScript; Including JavaScripts Including Stylesheets and JavaScripts in Twig ---------------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ No site would be complete without including JavaScript files and stylesheets. In Symfony, the inclusion of these assets is handled elegantly by taking @@ -1096,12 +1559,12 @@ advantage of Symfony's template inheritance. and JavaScript assets in Symfony. Symfony also packages another library, called Assetic, which follows this philosophy but allows you to do much more interesting things with those assets. For more information on - using Assetic see :doc:`/cookbook/assetic/asset_management`. + using Assetic see cookbook article :doc:`/cookbook/assetic/asset_management`. Start by adding two blocks to your base template that will hold your assets: -one called ``stylesheets`` inside the ``head`` tag and another called ``javascripts`` -just above the closing ``body`` tag. These blocks will contain all of the -stylesheets and JavaScripts that you'll need throughout your site: +one called ``stylesheets`` inside the ``head`` tag and another called +``javascripts`` just above the closing ``body`` tag. These blocks will contain +all of the stylesheets and JavaScripts that you'll need throughout your site:: .. configuration-block:: @@ -1148,7 +1611,10 @@ stylesheets and JavaScripts that you'll need throughout your site: That's easy enough! But what if you need to include an extra stylesheet or JavaScript from a child template? For example, suppose you have a contact page and you need to include a ``contact.css`` stylesheet *just* on that -page. From inside that contact page's template, do the following: +page. We want to add to the contents of a parent block instead of completely +overriding it. This is done by overriding ``stylesheets`` block, putting +``parent()`` Twig function into it to include everything from the ``stylesheets`` +block of the base template, and adding new assets we need just on this page:: .. configuration-block:: @@ -1174,286 +1640,29 @@ page. From inside that contact page's template, do the following: stop() ?> -In the child template, you simply override the ``stylesheets`` block and -put your new stylesheet tag inside of that block. Of course, since you want -to add to the parent block's content (and not actually *replace* it), you -should use the ``parent()`` Twig function to include everything from the ``stylesheets`` -block of the base template. - -You can also include assets located in your bundles' ``Resources/public`` folder. -You will need to run the ``php app/console assets:install target [--symlink]`` -command, which moves (or symlinks) files into the correct location. (target -is by default "web"). - -.. code-block:: html+twig - - - The end result is a page that includes both the ``main.css`` and ``contact.css`` stylesheets. -Global Template Variables -------------------------- - -During each request, Symfony will set a global template variable ``app`` -in both Twig and PHP template engines by default. The ``app`` variable -is a :class:`Symfony\\Bundle\\FrameworkBundle\\Templating\\GlobalVariables` -instance which will give you access to some application specific variables -automatically: - -``app.security`` - The security context. -``app.user`` - The current user object. -``app.request`` - The request object. -``app.session`` - The session object. -``app.environment`` - The current environment (dev, prod, etc). -``app.debug`` - True if in debug mode. False otherwise. - -.. configuration-block:: - - .. code-block:: html+twig - -

Username: {{ app.user.username }}

- {% if app.debug %} -

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

-

Application Environment: {{ app.environment }}

- {% endif %} - - .. code-block:: html+php - -

Username: getUser()->getUsername() ?>

- getDebug()): ?> -

Request method: getRequest()->getMethod() ?>

-

Application Environment: getEnvironment() ?>

- - -.. tip:: - - You can add your own global template variables. See the cookbook example - on :doc:`Global Variables `. - -.. index:: - single: Templating; The templating service - -Configuring and Using the ``templating`` Service ------------------------------------------------- - -The heart of the template system in Symfony is the templating ``Engine``. -This special object is responsible for rendering templates and returning -their content. When you render a template in a controller, for example, -you're actually using the templating engine service. For example:: - - return $this->render('article/index.html.twig'); - -is equivalent to:: - - use Symfony\Component\HttpFoundation\Response; - - $engine = $this->container->get('templating'); - $content = $engine->render('article/index.html.twig'); - - return $response = new Response($content); - -.. _template-configuration: - -The templating engine (or "service") is preconfigured to work automatically -inside Symfony. It can, of course, be configured further in the application -configuration file: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - # ... - templating: { engines: ['twig'] } - - .. code-block:: xml - - - - - - - - - twig - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - // ... - - 'templating' => array( - 'engines' => array('twig'), - ), - )); - -Several configuration options are available and are covered in the -:doc:`Configuration Appendix `. - -.. note:: - - The ``twig`` engine is mandatory to use the webprofiler (as well as many - third-party bundles). - -.. index:: - single: Template; Overriding templates +Including Assets from Bundles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. _overriding-bundle-templates: - -Overriding Bundle Templates ---------------------------- - -The Symfony community prides itself on creating and maintaining high quality -bundles (see `KnpBundles.com`_) for a large number of different features. -Once you use a third-party bundle, you'll likely need to override and customize -one or more of its templates. +Bundle related assets are located in the bundle ``Resources/public`` directory. +This files need to be moved or symlinked into the correct location, by default +``web/`` directory. This can be done by using ``assets:install`` console command:: -Suppose you've installed the imaginary open-source AcmeBlogBundle in your -project. And while you're really happy with everything, you want to override -the blog "list" page to customize the markup specifically for your application. -By digging into the ``Blog`` controller of the AcmeBlogBundle, you find the -following:: - - public function indexAction() - { - // some logic to retrieve the blogs - $blogs = ...; - - $this->render( - 'AcmeBlogBundle:Blog:index.html.twig', - array('blogs' => $blogs) - ); - } - -When the ``AcmeBlogBundle:Blog:index.html.twig`` is rendered, Symfony actually -looks in two different locations for the template: - -#. ``app/Resources/AcmeBlogBundle/views/Blog/index.html.twig`` -#. ``src/Acme/BlogBundle/Resources/views/Blog/index.html.twig`` - -To override the bundle template, just copy the ``index.html.twig`` template -from the bundle to ``app/Resources/AcmeBlogBundle/views/Blog/index.html.twig`` -(the ``app/Resources/AcmeBlogBundle`` directory won't exist, so you'll need -to create it). You're now free to customize the template. - -.. caution:: - - If you add a template in a new location, you *may* need to clear your - cache (``php app/console cache:clear``), even if you are in debug mode. - -This logic also applies to base bundle templates. Suppose also that each -template in AcmeBlogBundle inherits from a base template called -``AcmeBlogBundle::layout.html.twig``. Just as before, Symfony will look in -the following two places for the template: - -#. ``app/Resources/AcmeBlogBundle/views/layout.html.twig`` -#. ``src/Acme/BlogBundle/Resources/views/layout.html.twig`` - -Once again, to override the template, just copy it from the bundle to -``app/Resources/AcmeBlogBundle/views/layout.html.twig``. You're now free to -customize this copy as you see fit. - -If you take a step back, you'll see that Symfony always starts by looking in -the ``app/Resources/{BUNDLE_NAME}/views/`` directory for a template. If the -template doesn't exist there, it continues by checking inside the -``Resources/views`` directory of the bundle itself. This means that all bundle -templates can be overridden by placing them in the correct ``app/Resources`` -subdirectory. - -.. note:: - - You can also override templates from within a bundle by using bundle - inheritance. For more information, see :doc:`/cookbook/bundles/inheritance`. - -.. _templating-overriding-core-templates: - -.. index:: - single: Template; Overriding exception templates - -Overriding Core Templates -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Since the Symfony Framework itself is just a bundle, core templates can be -overridden in the same way. For example, the core TwigBundle contains -a number of different "exception" and "error" templates that can be overridden -by copying each from the ``Resources/views/Exception`` directory of the -TwigBundle to, you guessed it, the -``app/Resources/TwigBundle/views/Exception`` directory. - -.. index:: - single: Templating; Three-level inheritance pattern - -Three-level Inheritance ------------------------ - -One common way to use inheritance is to use a three-level approach. This -method works perfectly with the three different types of templates that were just -covered: - -* Create an ``app/Resources/views/base.html.twig`` file that contains the main - layout for your application (like in the previous example). Internally, this - template is called ``base.html.twig``; - -* Create a template for each "section" of your site. For example, the blog - functionality would have a template called ``blog/layout.html.twig`` that - contains only blog section-specific elements; - - .. code-block:: html+twig - - {# app/Resources/views/blog/layout.html.twig #} - {% extends 'base.html.twig' %} - - {% block body %} -

Blog Application

- - {% block content %}{% endblock %} - {% endblock %} - -* Create individual templates for each page and make each extend the appropriate - section template. For example, the "index" page would be called something - close to ``blog/index.html.twig`` and list the actual blog posts. +.. code-block:: bash - .. code-block:: html+twig + $ php app/console assets:install target [--symlink] - {# app/Resources/views/blog/index.html.twig #} - {% extends 'blog/layout.html.twig' %} +Now, they can be included in a template: - {% block content %} - {% for entry in blog_entries %} -

{{ entry.title }}

-

{{ entry.body }}

- {% endfor %} - {% endblock %} - -Notice that this template extends the section template (``blog/layout.html.twig``) -which in turn extends the base application layout (``base.html.twig``). This is -the common three-level inheritance model. +.. code-block:: html+twig -When building your application, you may choose to follow this method or simply -make each page template extend the base application template directly -(e.g. ``{% extends 'base.html.twig' %}``). The three-template model is a -best-practice method used by vendor bundles so that the base template for a -bundle can be easily overridden to properly extend your application's base -layout. + .. index:: single: Templating; Output escaping + single: Templating; Cross Site Scripting Output Escaping --------------- @@ -1462,7 +1671,7 @@ When generating HTML from a template, there is always a risk that a template variable may output unintended HTML or dangerous client-side code. The result is that dynamic content could break the HTML of the resulting page or allow a malicious user to perform a `Cross Site Scripting`_ (XSS) attack. Consider -this classic example: +this classic example:: .. configuration-block:: @@ -1474,14 +1683,14 @@ this classic example: Hello -Imagine the user enters the following code for their name: +Imagine the user enters the following code for their name:: .. code-block:: html Without any output escaping, the resulting template will cause a JavaScript -alert box to pop up: +alert box to pop up:: .. code-block:: html @@ -1493,7 +1702,7 @@ inside the secure area of an unknowing, legitimate user. The answer to the problem is output escaping. With output escaping on, the same template will render harmlessly, and literally print the ``script`` -tag to the screen: +tag to the screen:: .. code-block:: html @@ -1507,17 +1716,17 @@ escape where necessary. Output Escaping in Twig ~~~~~~~~~~~~~~~~~~~~~~~ -If you're using Twig templates, then output escaping is on by default. This +**If you're using Twig templates, then output escaping is on by default**. This means that you're protected out-of-the-box from the unintentional consequences of user-submitted code. By default, the output escaping assumes that content is being escaped for HTML output. -In some cases, you'll need to disable output escaping when you're rendering +In some cases, you'll need to **disable output escaping** when you're rendering a variable that is trusted and contains markup that should not be escaped. Suppose that administrative users are able to write articles that contain HTML code. By default, Twig will escape the article body. -To render it normally, add the ``raw`` filter: +To render it normally, add the ``raw`` filter:: .. code-block:: twig @@ -1530,9 +1739,9 @@ the Twig documentation. Output Escaping in PHP ~~~~~~~~~~~~~~~~~~~~~~ -Output escaping is not automatic when using PHP templates. This means that +**Output escaping is not automatic when using PHP templates**. This means that unless you explicitly choose to escape a variable, you're not protected. To -use output escaping, use the special ``escape()`` view method: +use output escaping, use the special ``escape()`` view method:: .. code-block:: html+php @@ -1540,25 +1749,54 @@ use output escaping, use the special ``escape()`` view method: By default, the ``escape()`` method assumes that the variable is being rendered within an HTML context (and thus the variable is escaped to be safe for HTML). -The second argument lets you change the context. For example, to output something -in a JavaScript string, use the ``js`` context: +The second argument lets you change the context. For example, to output +something in a JavaScript string, use the ``js`` context:: .. code-block:: html+php var myMsg = 'Hello escape($name, 'js') ?>'; .. index:: - single: Templating; Formats + single: Templating; Twig debugging Debugging --------- +Important, but unrelated to the topic of templating is the second argument +to the ``AppKernel()`` constructor inside front controller being used. This +specifies if the application should run in "debug mode" or not. Regardless of +the environment, a Symfony application can therefore run with debug mode set to +``true`` or ``false``. + +Internally, the value of the debug mode becomes the ``kernel.debug`` +parameter used inside the service container. If you look inside the +default application configuration file, you'll see the parameter used, +for example, to turn the debug mode on or off when using the Twig:: + +.. configuration-block:: + + .. code-block:: yaml + + twig: + debug: '%kernel.debug%' + # ... + + .. code-block:: xml + + + + .. code-block:: php + + $container->loadFromExtension('twig', array( + 'debug' => '%kernel.debug%', + // ... + )); + When using PHP, you can use :phpfunction:`var_dump` if you need to quickly find the value of a variable passed. This is useful, for example, inside your controller. The same can be achieved when using Twig thanks to the Debug -extension. - -Template parameters can then be dumped using the ``dump`` function: +extension. Template parameters can then be dumped using Twig ``dump()`` +function, which internally, uses the PHP `var_dump()` function: .. code-block:: html+twig @@ -1571,15 +1809,14 @@ Template parameters can then be dumped using the ``dump`` function: {% endfor %} -The variables will only be dumped if Twig's ``debug`` setting (in ``config.yml``) -is ``true``. By default this means that the variables will be dumped in the -``dev`` environment but not the ``prod`` environment. +.. index:: + single: Templating; Twig Syntax Checking Syntax Checking --------------- You can check for syntax errors in Twig templates using the ``twig:lint`` -console command: +console command:: .. code-block:: bash @@ -1589,63 +1826,6 @@ console command: # or by directory: $ php app/console twig:lint app/Resources/views -.. _template-formats: - -Template Formats ----------------- - -Templates are a generic way to render content in *any* format. And while in -most cases you'll use templates to render HTML content, a template can just -as easily generate JavaScript, CSS, XML or any other format you can dream of. - -For example, the same "resource" is often rendered in several formats. -To render an article index page in XML, simply include the format in the -template name: - -* *XML template name*: ``article/index.xml.twig`` -* *XML template filename*: ``index.xml.twig`` - -In reality, this is nothing more than a naming convention and the template -isn't actually rendered differently based on its format. - -In many cases, you may want to allow a single controller to render multiple -different formats based on the "request format". For that reason, a common -pattern is to do the following:: - - public function indexAction(Request $request) - { - $format = $request->getRequestFormat(); - - return $this->render('article/index.'.$format.'.twig'); - } - -The ``getRequestFormat`` on the ``Request`` object defaults to ``html``, -but can return any other format based on the format requested by the user. -The request format is most often managed by the routing, where a route can -be configured so that ``/contact`` sets the request format to ``html`` while -``/contact.xml`` sets the format to ``xml``. For more information, see the -:ref:`Advanced Example in the Routing chapter `. - -To create links that include the format parameter, include a ``_format`` -key in the parameter hash: - -.. configuration-block:: - - .. code-block:: html+twig - - - PDF Version - - - .. code-block:: html+php - - - PDF Version - - Final Thoughts -------------- @@ -1675,17 +1855,24 @@ Learn more from the Cookbook ---------------------------- * :doc:`/cookbook/templating/PHP` +* :doc:`/cookbook/templating/namespaced_paths` * :doc:`/cookbook/controller/error_pages` * :doc:`/cookbook/templating/twig_extension` +* :doc:`/cookbook/templating/global_variables` +* :doc:`/cookbook/templating/render_without_controller` .. _`Twig`: http://twig.sensiolabs.org -.. _`KnpBundles.com`: http://knpbundles.com -.. _`Cross Site Scripting`: https://en.wikipedia.org/wiki/Cross-site_scripting -.. _`Output Escaping`: http://twig.sensiolabs.org/doc/api.html#escaper-extension -.. _`tags`: http://twig.sensiolabs.org/doc/tags/index.html +.. _`here`: http://twig.sensiolabs.org/documentation +.. _`Twig extensions`: http://twig.sensiolabs.org/doc/api.html#using-extensions +.. _`functions`: http://twig.sensiolabs.org/doc/functions/index.html .. _`filters`: http://twig.sensiolabs.org/doc/filters/index.html -.. _`add your own extensions`: http://twig.sensiolabs.org/doc/advanced.html#creating-an-extension -.. _`hinclude.js`: http://mnot.github.io/hinclude/ +.. _`tags`: http://twig.sensiolabs.org/doc/tags/index.html +.. _`tests`: http://twig.sensiolabs.org/doc/tests/index.html +.. _`add your own extensions`: http://twig.sensiolabs.org/doc/advanced.html .. _`with_context`: http://twig.sensiolabs.org/doc/functions/include.html .. _`include() function`: http://twig.sensiolabs.org/doc/functions/include.html .. _`{% include %} tag`: http://twig.sensiolabs.org/doc/tags/include.html +.. _`hinclude.js`: http://mnot.github.io/hinclude/ +.. _`KnpBundles.com`: http://knpbundles.com +.. _`Cross Site Scripting`: https://en.wikipedia.org/wiki/Cross-site_scripting +.. _`Output Escaping`: http://twig.sensiolabs.org/doc/api.html#escaper-extension \ No newline at end of file