Create and use templates


<img src="{{ absolute_url(asset('images/logo.png')) }}" alt="Symfony!" />
Just so you know, Controller (controller) is responsible for processing every request entering the symfony program. In effect, controllers delegate most of the heavy lifting elsewhere so that code can be tested and reused. When a controller needs to generate HTML, CSS, or other content, it gives the work to a template engine. In this chapter, you'll learn how to write powerful templates for returning content to users, populating emails, and more. You'll also learn shortcuts, clever ways to extend templates, and how to reuse template code.

For how to render the template, please see the controller of "Framework Start".

Template

Template is to generate any text file based on text format (html, xml, csv, LaTex...). The most familiar type of template we are most familiar with is the php template - a text file containing text and PHP code that is parsed by the PHP engine:

<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to Symfony!</title>
    </head>
    <body>
        <h1><?php echo $page_title ?></h1>
 
        <ul id="navigation">            <?php foreach ($navigation as $item); ?>
                <li>
                    <a href="<?php echo $item->getHref(); ?>">                        <?php echo $item->getCaption(); ?>
                    </a>
                </li>            <?php endforeach; ?>
        </ul>
    </body>
</html>

However, there is a more powerful template language in the symfony framework It's called Twig. Twig allows you to write concise, easy-to-read and designer-friendly templates, which are much more powerful than PHP templates in several aspects.

<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to Symfony!</title>
    </head>
    <body>
        <h1>{{ page_title }}</h1>
 
        <ul id="navigation">            {% for item in navigation %}
                <li><a href="{{ item.href }}">{{ item.caption }}</a></li>            {% endfor %}
        </ul>
    </body>
</html>

Twig defines three special syntaxes:

  • {{ ... }}
  • "Say something": Output a variable value or the result of an expression to the template.
  • {% ... %}
  • "What to do": *tag (tag)* that controls template logic, used to execute statements, such as for loops Statements etc.
  • {# ... #}
  • "Comment": It is equivalent to PHP's /* comment */ syntax. It is used to comment single and multiple lines. The content of the comment is not output as a page.

twig also contains filters, which can change the output content before the template is rendered. The following example makes the title variable all capitalized before being rendered:

   {{ title|upper }}

Twig has a large number of built-in tags and variable filters that can be used by default. You can even take advantage of Twig extensions to add your own custom regulators and functions (and more).

Registering a Twig extension is very easy, just create a new service and tag it with Twig.extension.

Twig code is very similar to PHP code, and there are subtle differences between the two. The following example uses a standard for tag and the cycle function to output 10 div tags, alternating with odd, even css classes show.

{% for i in 0..10 %}
    <div class="{{ cycle(['odd', 'even'], i) }}">
      <!-- some HTML here -->
    </div>{% endfor %}

The template routines in this chapter will be displayed using both twig and php.

If you don't use Twig or disable it, you need to use the kernel.execption event to implement your own exception handling.

Why use twig?

The twig template is for simplicity and does not deal with php tags. This is the case in design: the twig template is only responsible for presentation, without considering logic. The more you use Twig, the more you'll appreciate it and benefit from its features. Of course, you will also be liked by web designers all over the world.

There are many things that Twig can do but PHP cannot, such as space control, sandboxing, automatic html escaping, manual context output escaping, and custom functions that "only affect the template" and Regulator. twig contains some small functions to make writing templates more convenient and faster. Consider the following example, which combines a logical loop with an if statement:

<ul>   
 {% for user in users if user.active %}
        <li>{{ user.username }}</li>    {% else %}
        <li>No users found</li>    {% endfor %}</ul>

Twig Template Caching

Twig is fast, each Twig template is compiled into a native PHP class and cached. Compiled classes are saved in the var/cache/{environment}/twig directory (where {environment} is the environment, such as dev and prod), and can be debugged at the same time in some cases, which is very useful. For more details about environments please refer to: Environment

When debug mode is available (devEnvironment), if a twig template changes , will be automatically recompiled. This means you can modify your templates as you go without having to worry about clearing the cache.

When debug mode is turned off (prod environment), you must manually clear the Twig cache directory in order to regenerate Twig templates. Remember to do this when deploying your program.

Template inheritance and layout

Most of the time, templates have common elements in the project, such as header, footer, sidebar, etc. In Symfony, we will approach this problem from a different perspective. A template can be decorated by other templates. This works much like PHP classes, template inheritance allows you to create a base "layout" template that contains all the common elements of your site and is defined as blocks (like a "contains basic methods" PHP base class"). A child template can inherit the layout base template and override any of its blocks (just like "PHP subclasses override specific methods in the parent class").

First create a layout basic file:

Twig:{# app/Resources/views/base.html.twig #}<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Test Application{% endblock %}</title>
    </head>
    <body>
        <div id="sidebar">            {% block sidebar %}
                <ul>
                    <li><a href="/">Home</a></li>
                    <li><a href="/blog">Blog</a></li>
                </ul>            {% endblock %}
        </div>
 
        <div id="content">            {% block body %}{% endblock %}
        </div>
    </body>
</html>
PHP:<!-- app/Resources/views/base.html.php -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title><?php $view['slots']->output('title', 'Test Application') ?></title>
    </head>
    <body>
        <div id="sidebar">            <?php if ($view['slots']->has('sidebar')): ?>
                <?php $view['slots']->output('sidebar') ?>
            <?php else: ?>
                <ul>
                    <li><a href="/">Home</a></li>
                    <li><a href="/blog">Blog</a></li>
                </ul>            <?php endif ?>
        </div>
 
        <div id="content">            <?php $view['slots']->output('body') ?>
        </div>
    </body>
</html>

Although the discussion is about Twig template inheritance, the way of thinking is the same between twig and php templates of.

This template defines a simple two-column html page. In this example, three {% block %} areas are defined (i.e. title, sidebar and body). Each block can be overridden by subtemplates that inherit it, or the current default implementation can be retained. The template can also be rendered (output) directly. However, only the content defined by the basic template is displayed at this time, and title, sidebar and body will remain at their default values.

A child template looks like this:

Twig:{# app/Resources/views/blog/index.html.twig #}{% extends 'base.html.twig' %} {% block title %}My cool blog posts{% endblock %} {% block body %}
    {% for entry in blog_entries %}
        <h2>{{ entry.title }}</h2>
       <p>{{ entry.body }}</p>    {% endfor %}{% endblock %}
php:<!-- app/Resources/views/blog/index.html.php --><?php $view->extend('base.html.php') ?> <?php $view['slots']->set('title', 'My cool blog posts') ?> <?php $view['slots']->start('body') ?>
    <?php foreach ($blog_entries as $entry): ?>
        <h2><?php echo $entry->getTitle() ?></h2>
        <p><?php echo $entry->getBody() ?></p>    <?php endforeach ?><?php $view['slots']->stop() ?>

The parent template is represented by a special string syntaxbase.html.twig , this path is relative to the app/Resources/views directory of the entire project. You can also use ::base.html.twig with the same logical name. See template name and location below.

The keyword for template inheritance is the {% extends %} tag. This tag tells the template engine to first evaluate the parent template, which sets the layout and defines several blocks. Then the child template is rendered, and the two blocks title and body defined in the parent template in the above example will be replaced by the block content of the same name in the child template. Depending on the value of blog_entries, the output content may be as follows:

<!DOCTYPE html><html>
    <head>
        <meta charset="UTF-8">
        <title>My cool blog posts</title>
    </head>
    <body>
        <div id="sidebar">
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/blog">Blog</a></li>
            </ul>
        </div>         <div id="content">
            <h2>My first post</h2>
            <p>The body of the first post.</p>             <h2>Another post</h2>
            <p>The body of the second post.</p>
        </div>
    </body></html>

Note that since the sidebar block is not defined in the child template, the content from the parent template will be displayed. The content within the {% block %} tag in the parent template is always used as the default value.

You can carry out template inheritance at any number of levels. Symfony projects generally use the "three-level inheritance" model to organize templates and pages. Please refer to how to use inheritance to organize your Twig templates.

When using template inheritance, please note:

  • If you use {% extends %} in a template, it must be the first tag in the template .

  • The more {% block %} tags in your base (layout) template, the better. Remember, the child template does not have to define all blocks in the parent template . The more blocks are defined in the base template, the more flexible your layout will be.

  • If you find duplicate content in multiple templates, this may mean you need to define a {% block %}## for that content in the parent template #. In some cases, a better solution might be to put the content into a new template and include it within that template. (See below: Including other templates)

  • If you need to get the content of a block from the parent template, you can use the

    {{ parent() }} function . This is useful if you just want to add new content on top of the parent block, rather than overwriting it completely:

  • {% block sidebar %}
        <h3>Table of Contents</h3>
         {# ... #}     {{ parent() }}{% endblock %}
Name and storage location of the template ¶

Default In this case, templates can be stored in two different locations:

app/Resources/views

The program-level views directory can store the basic templates of the entire program (program layout and bundle templates), as well as those "used to override third-party bundles" "Template" template (how to override the template of a third-party bundle).

path/to/bundle/Resources/views

The template of each third-party bundle will be stored in its own

Resources/views/ directory (or subdirectory). When you plan to share your bundle, you should put it in the bundle, not the app/ directory.

More often the templates you want to use are in the

app/Resources/views/ directory. The template path you need is relative to this directory. For example, to render/inherit app/Resources/views/base.html.twig, you need to use the path of base.html.twig, but to render app/ Resources/views/blog/index.html.twig, you need to use the blog/index.html.twig path.

Introducing templates into Bundle

Symfony uses

bundle:directory:filename string syntax to represent templates. This can represent many different types of templates, each stored in a specific path:

  • AcmeBlogBundle:Blog:index.html.twig is used to specify a specific page template. The string is divided into three parts, each part separated by a colon (:), with the following meaning:
  1. AcmeBlogBundle : (bundle) The template is located in AcmeBlogBundle, such as src/Acme/BlogBundle;

  2. Blog: (Directory) indicates that the template is located in the Blog subdirectory of Resourcs/views;

  3. ##index.html.twig

    : (Filename) The actual name of the file is index.html.twig.

  4. Assuming that the AcmeBlogBundle is located at
src/Acme/BlogBundle

, the final path will be: src/Acme/BlogBundle/Resources/views/Blog/index. html.twig

  • AcmeBlogBundle::layout.html.twig This syntax points to the parent template of AcmeBlogBundle. Without the middle "directory" part (such as blog), the template should be located in AcmeBlogBundle's Resources/views/layout.html.twig. Yes, the two colons in the middle mean that the "controller" subdirectory part is ignored.

In the article How to overwrite the template of a third-party bundle, you will learn how the template located in the AcmeBlogBundle is app/Resources/AcmeBlogBundle/views/ directory Overridden by a template with the same name, this method gives us a powerful way to override the bundle template provided by the bundle author.

The template naming syntax may look familiar - it is similar to the conventions mentioned in Controller Naming Patterns.

Template suffix ¶

Each template has two extensions, used to specify the format (format) and template engine (engine).

##File NameFormatEngineHTMLTwigHTMLPHPCSSTwig

By default, any template in Symfony can be written as a Twig or PHP engine, and the suffix (.twig or .php) determines which engine to use. The first part of the suffix (.html,.css) indicates the final generated format. Unlike the engine, which determines how symfony parses the template, this is a very simple strategy to use, you can use HTML (index.html.twig), XML (index.xml.twig) or any other format as a rendered resource. For more details, please read the Template Format section.

The available "engines" section is configurable and it is even possible to add a new engine. Please see How to Configure and Use Template Services for more details.

Tags and Helps ¶

You already know the basics of templates, how they are named and how to use template inheritance. The hardest part is over. Next, we'll look at the numerous tools available to help us with common template tasks, such as including other templates, linking to a page, or including images.

Several special Twig tags and functions are built into the Symfony framework to help template designers simplify their work. In PHP, the template system provides an extensible helper system for providing useful functionality in the template context.

You have seen some built-in Twig tags, such as ({% block %} & {% extends %}), etc., as well as PHP helper $view['slots']. Now, you will learn more.

Introducing other templates

You often need to include the same template or code snippet in multiple different pages. For example, in a "news article" program, the template code used to display articles may be used on the text page, or a page that displays "popular articles", or even a list page of "latest articles", etc.

When you need to reuse some PHP code, you usually put the code into a PHP class or function. You can do this in templates as well. By putting reusable code into a template of its own, and then containing that template from other templates. First, create a reusable template as follows:

Twig:{# app/Resources/views/article/article_details.html.twig #}<h2>{{ article.title }}</h2>
<h3 class="byline">by {{ article.authorName }}</h3>
 
<p>    {{ article.body }}</p>
php:<!-- app/Resources/views/article/article_details.html.php -->
<h2><?php echo $article->getTitle() ?></h2>
<h3 class="byline">by <?php echo $article->getAuthorName() ?></h3>
 
<p>    <?php echo $article->getBody() ?></p>

Introducing this template into any other template is simple:

Twig:{# app/Resources/views/article/list.html.twig #}{% extends 'layout.html.twig' %} {% block body %}
    <h1>Recent Articles<h1>
     {% for article in articles %}
        {{ include('article/article_details.html.twig', { 'article': article }) }}
   {% endfor %}{% endblock %}
php:<!-- app/Resources/article/list.html.php --><?php $view->extend('layout.html.php') ?> 
    <?php $view['slots']-               >start('body') ?>    <h1>Recent Articles</h1>     <?php foreach ($articles as $article): ?>        <?php echo $view->render(            'Article/article_details.html.php',            array('article' => $article)        ) ?>    <?php endforeach ?><?php $view['slots']->stop()
 ?>

When this template is included, use { { include() }} tag. Note that template naming follows the same typical conventions. Use the article variable in the article_details.html.twig template, which is what we pass into the template. In this case, you don't have to do this at all, since all variables available in the list.html.twig template are also available in the article_details.html.twig (unless You set with_context to false).

{'article':article}The syntax is the writing of standard Twig hash maps (that is, an array of key-value pairs). If you need to pass multiple elements, you can write {'foo': foo, 'bar': bar}.

Link to page

Creating a link to another page in your program is a common thing for templates. Use the path Twig function (or the router helper in PHP) to generate URLs based on routing configuration instead of hard-coding URLs in templates. Later, if you want to change the URL of a specific page, you only need to change the routing configuration; the template will automatically generate the new URL.

For example, if we plan to link to the "_welcome" page, first define its routing configuration:

Annotations:// src/AppBundle/Controller/WelcomeController.php // ...use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class WelcomeController extends Controller{
    /**
     * @Route("/", name="_welcome")
     */
    public function indexAction()
    {
        // ...
   }}
YAML:# app/config/routing.yml_welcome:
    path:     /
    defaults: { _controller: AppBundle:Welcome:index }
XAML:<!-- app/config/routing.yml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="_welcome" path="/">
        <default key="_controller">AppBundle:Welcome:index</default>
    </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('_welcome', new Route('/', array(
    '_controller' => 'AppBundle:Welcome:index',))); return $collection;

To link to the page, just use Twig's path function to specify this Just route it.

Twig:<a href="{{ path('_welcome') }}">Home</a>
php:<a href="<?php echo $view['router']->path('_welcome') ?>">Home</a>

As expected, it generated the URL /. Now, deal with a more complex route:

Annotations:// src/AppBundle/Controller/ArticleController.php // ...use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class ArticleController extends Controller{
    /**
     * @Route("/article/{slug}", name="article_show")
     */
    public function showAction($slug)
    {
        // ...
    }}
TAML:# app/config/routing.ymlarticle_show:
    path:     /article/{slug}
    defaults: { _controller: AppBundle:Article:show }
PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('article_show', new Route('/article/{slug}', array(
    '_controller' => 'AppBundle:Article:show',))); return $collection;
XAML:<!-- app/config/routing.xml --><?xml version="1.0" encodin
g="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="article_show" path="/article/{slug}">
        <default key="_controller">AppBundle:Article:show</default>
    </route></routes>

In this case, you need to specify the route name () as well as a . Use this route to redefine the template mentioned earlier and link to the article correctly.

Twig:{# app/Resources/views/article/recent_list.html.twig #}{% for article in articles %}
    <a href="{{ path('article_show', {'slug': article.slug}) }}">        {{ article.title }}
    </a>{% endfor %}
php:<!-- app/Resources/views/Article/recent_list.html.php --><?php foreach ($articles in $article): ?>
    <a href="<?php echo $view['router']->path('article_show', array(
        'slug' => $article->getSlug(),
    )) ?>">        <?php echo $article->getTitle() ?>
    </a><?php endforeach ?>

You can use Twig’s url function to generate the absolute path:

Twig:<a href="{{ url('_welcome') }}">Home</a>
php:<a href="<?php echo $view['router']->url(    '_welcome',    array()) ?>">Home</a>

Link to Assets

Templates usually also require some images, Javascript, style files and other web assets. Of course you can hardcode their paths. For example /images/logo.png. But Symfony provides a more dynamic choice through the Twig function asset().

Twig:<img src="{{ asset('images/logo.png') }}" alt="Symfony!" /> <link href="{{ asset('css/blog.css') }}" rel="stylesheet" />
php:<img src="<?php echo $view['assets']->getUrl('images/logo.png') ?>" alt="Symfony!" />
 
<link href="<?php echo $view['assets']->getUrl('css/blog.css') ?>" rel="stylesheet" />

asset The main purpose of the function is to make your program more portable. If your program is in the host root directory (such as http://example.com), the generated path should be /images/logo.png. But if your program is located in a subdirectory (such as http://example.com/my_app), the asset path should be generated with the subdirectory (such as /my_app/images/logo .png). The asset function is responsible for managing these, and it generates the corresponding correct path based on "how your program is used".

In addition, if you use the asset function, symfony can automatically append a query string (query string) to your assets to ensure that the updated static resources will not be deployed during deployment. cache. For example, /images/logo.png might look like /images/logo.png?v2. Refer to the versionConfiguration article to learn more.

If you need the absolute URL of assets resources, you can use absolute_url() Twig function:

<img src="{{ absolute_url(asset('images/logo.png')) }}" alt="Symfony!" />

Include stylesheets and Javascript in Twig

Every website cannot be completely without style sheets and javascript files. In Symfony, these can be handled elegantly using template inheritance.

This section teaches you the ideas behind including stylesheet and javaScript resources. Symfony supports another class library called Assetic, which allows you to do more interesting things with these resources while following this idea. Refer to How to use Assetic for asset management for more details.

First add two blocks to your basic layout template to save your resources, one is called stylesheets, and is placed in the head tag Inside, the other one is called javascript and is placed one line above the body closing tag. These blocks will contain all the stylesheets and javascripts you need for your entire site.

Twig:{# app/Resources/views/base.html.twig #}<html>
    <head>        {# ... #}         {% block stylesheets %}
            <link href="{{ asset('css/main.css') }}" rel="stylesheet" />        {% endblock %}
    </head>
    <body>        {# ... #}         {% block javascripts %}
            <script src="{{ asset('js/main.js') }}"></script>        {% endblock %}
    </body>
</html>
php:// app/Resources/views/base.html.php<html>    <head>        <?php ... ?>         <?php $view['slots']->start('stylesheets') ?>            <link href="<?php echo $view['assets']->getUrl('css/main.css') ?>" rel="stylesheet" />        <?php $view['slots']->stop() ?>    </head>    <body>        <?php ... ?>         <?php $view['slots']->start('javascripts') ?>            <script src="<?php echo $view['assets']->getUrl('js/main.js') ?>"></script>      
  <?php $view['slots']->stop() ?>    </body>
</html>

This is too simple! But what if you want to include an additional stylesheet or javascript from the subtemplate? For example, let's say you have a contact page that needs to include a contact.css style sheet, only is used on that page. In the template of the contact page, you can implement it like this:

Twig:{# app/Resources/views/contact/contact.html.twig #}{% extends 'base.html.twig' %} {% block stylesheets %}
    {{ parent() }} 
   <link href="{{ asset('css/contact.css') }}" rel="stylesheet" />{% endblock %} {# ... #}
php:// app/Resources/views/contact/contact.html.twig<?php $view->extend('base.html.php') ?> <?php $view['slots']->start('stylesheets') ?>
    <link href="<?php echo $view['assets']->getUrl('css/contact.css') ?>" rel="stylesheet" /><?php $view['slots']->stop() ?>

In the child template, you only need to override the stylesheets block and place your new stylesheet tags in the block. Of course, since you just want to add it to the content of the parent block (rather than actually replacing them), you need to first use the parent() function to get the base template All content in the stylesheets block.

You can also include assets located in your bundle's Resources/public folder. You need to run the php bin/console assets:install target [–symlink] command, which will move (or symlink) the files to the correct location (the default target location is the "web" folder).

<link href="{{ asset('bundles/acmedemo/css/contact.css') }}" rel="stylesheet" />

The final result is that the page contains two style sheets main.css and contact.css.

Reference Request, User or Session object

Symfony gives you a global app variable in Twig, which can be used to access the current Users, requests, and more objects.

Refer to How to access User, Request, Session and more objects through app variables in Twig for details.

Output escaping

When rendering any content, Twig automatically performs "output escaping" to protect you from Cross Site Scripting (XSS) cross-site attack.

Assume description is I <3 this product:

<!-- output escaping is on automatically -->{{ description }} <!-- I &lt3 this product -->
 
<!-- disable output escaping with the raw filter -->{{ description|raw }} <!-- I <3 this product -->

PHP templates do not automatically escape the content.

For more details, see How to escape template output.

Summary

The template engine in Symfony is a powerful tool that you can use to generate content including HTML, XML and any other format as needed. Although it is common for templates to be generated from a controller, it is not required. The Response object returned by the controller can use a template or not.

// creates a Response object whose content is the rendered template$response = $this->render('article/index.html.twig'); // creates a Response object whose content is simple text$response = new Response('response content');

Symfony's templates are very flexible. By default, they support traditional PHP templates and sleek and powerful Twig templates. They both have very rich helper functions to perform some common tasks. Symfony recommends using Twig templates because it is more concise, efficient, and can better handle inheritance, etc.

Overall, it is a powerful tool when you deal with template problems. In some cases you may not need to render the template, and in symfony this is absolutely no problem.

    blog/index.html.twig
    blog/index.html.php
    blog/index.css .twig