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.
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 (dev
Environment), 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
includeit 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/viewsThe 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/viewsThe 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.
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.
¶
Symfony usesbundle: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:
AcmeBlogBundle
: (
bundle) The template is located in AcmeBlogBundle, such as src/Acme/BlogBundle;
Blog
: (
Directory) indicates that the template is located in the Blogsubdirectory of
Resourcs/views;
- ##index.html.twig
: (
Filename
) The actual name of the file is index.html.twig. Assuming that the AcmeBlogBundle is located at
, the final path will be: In the article How to overwrite the template of a third-party bundle, you will learn how the template located in the AcmeBlogBundle is The template naming syntax may look familiar - it is similar to the conventions mentioned in Controller Naming Patterns. Each template has two extensions, used to specify the format (format) and template engine (engine). By default, any template in Symfony can be written as a Twig or PHP engine, and the suffix ( 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. 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 ( 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: Introducing this template into any other template is simple: When this template is included, use Creating a link to another page in your program is a common thing for templates. Use the For example, if we plan to link to the "_welcome" page, first define its routing configuration: To link to the page, just use Twig's As expected, it generated the URL 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. You can use Twig’s Templates usually also require some images, Javascript, style files and other web assets. Of course you can hardcode their paths. For example In addition, if you use the If you need the absolute URL of assets resources, you can use 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 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 In the child template, you only need to override the You can also include assets located in your bundle's The final result is that the page contains two style sheets Symfony gives you a global Refer to How to access User, Request, Session and more objects through app variables in Twig for details. When rendering any content, Twig automatically performs "output escaping" to protect you from Cross Site Scripting (XSS) cross-site attack. Assume PHP templates do not automatically escape the content. For more details, see How to escape template output. 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. 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. 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. 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. Template suffix ¶
##File Name Format Engine blog/index.html.twig HTMLTwig blog/index.html.php HTMLPHP blog/index.css .twig CSSTwig .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. Tags and Helps ¶
{% block %}
& {% extends %}
), etc., as well as PHP helper $view['slots']
. Now, you will learn more. Introducing other templates ¶
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>
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()
?>
{ { 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 ¶
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. 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;
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>
/
. 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>
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 ?>
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 ¶
/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". 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. absolute_url()
Twig function: <img src="{{ absolute_url(asset('images/logo.png')) }}" alt="Symfony!" />
Include stylesheets and Javascript in Twig ¶
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>
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() ?>
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. 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" />
main.css
and contact.css
. Reference Request, User or Session object ¶
app
variable in Twig, which can be used to access the current Users, requests, and more objects. Output escaping ¶
description
is I <3 this product
: <!-- output escaping is on automatically -->{{ description }} <!-- I <3 this product -->
<!-- disable output escaping with the raw filter -->{{ description|raw }} <!-- I <3 this product -->
Summary ¶
// 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');