创建和使用模板

3.3 版本
维护中的版本

如同 前文 所述,控制器(controller)负责处理每一个进入symfony程序的请求,通常以输出模板来生成响应内容作为结束。

现实中,控制器把大部分的繁重工作都委托给了其他地方,以令代码能够被测试和复用。当一个controller需要生成HTML、CSS或者其他内容时,它把这些工作给了一个模板引擎。

在本文中,你将学习如何编写功能强大的模板,用于把内容返回给用户、填充email,等等。你还将学会快捷方法,用聪明的方式来扩展模板,以及如何复用模板代码。

模板 

模板就是生成基于文本格式(html,xml,csv,LaTex…)的任何文本文件。我们最熟悉的模板类型就是 PHP 模板——包含文字和PHP代码的被PHP引擎解析的文本文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!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>

但是,symfony 框架中有一个更强大的模板语言叫作Twig。Twig可令你写出简明易读且对设计师友好的模板,在几个方面比PHP模板强大许多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!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定义了三种特殊的语法:

{{ ... }}
“说些什么”:输出一个变量值或者一个表达式的结果到模板。
{% ... %}
“做些什么”:控制模板逻辑的*tag(标签)*,用于执行声明,如for循环语句等。
{# ... #}
“进行注释”:它相当于PHP的 /* comment */ 语法。它用于注释单行和多行。注释的内容不作为页面输出。

Twig也包含 filters,它可以在模板输出之前改变输出内容。下例让title变量在被输出之前全部大写:

1
{{ title|upper }}

Twig内置了大量的标签(tags)和变量调节器(filters),默认就可以使用。你甚至可以利用Twig扩展来添加你自己的 自定义 调节器和函数(乃至更多)。

Twig代码很像PHP代码,两者有微妙的区别。下例使用了一个标准的 for 标签和 cycle 函数来输出10个div 标签,用oddeven css类交替显示。

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

本章的模板例程,将同时使用Twig和PHP来展示。

为什么使用Twig?

Twig模板就是为了简单而不去处理PHP标签。设计上即是如此:Twig模板只负责呈现,而不去考虑逻辑。你用Twig越多,你就越会欣赏它,并从它的特性中受益。当然,你也会被普天下的网页设计者喜欢。

还有很多Twig可以做但是PHP不可以的事,如空格控制、沙盒、自动html转义、手动上下文输出转义,以及包容“只会影响模板”的自定义函数和调节器。Twig包含一些小功能,使得写模板时更加方便快捷。请看下例,它结合了逻辑循环和 if 语句:

1
2
3
4
5
6
7
<ul>
    {% for user in users if user.active %}
        <li>{{ user.username }}</li>
    {% else %}
        <li>No users found</li>
    {% endfor %}
</ul>

Twig模板缓存 

Twig超快的原因是,Twig模板被编译成原生PHP类并且缓存起来。不用担心,这一切自动完成,毋须你做任何事。而且在开发时,当你做出任何改变时,Twig足够智能地重新编译你的模板。这意味着,Twig在产品环境下极快,在开发环境却极易使用。

模板继承和布局 

大多数的时候,模板在项目中都有通用的元素,比如header,footer,sidebar等等。在Symfony中,我们将采用不同的思考角度来对待这个问题。一个模板可以被另外的模板装饰。这个的工作原理跟PHP类非常像,模板继承让你可以创建一个基础“layout”模板,它包含你的站点所有通用元素,并被定义成 blocks(如同一个“包含基础方法的PHP基类”)。一个子模板可以继承layout基础模板并覆写它的任何一个block(就像“PHP子类覆写父类中的特定方法”)。

首先创建一个layout基础文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{# 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- 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>

Note

虽然讨论的是关于Twig的模板继承,但在思维方式上Twig和PHP模板之间是相同的。

该模板定义了一个简单的两列式html页面。在本例中,三处 {% block %} 区域被定义了(即titlesidebarbody)。每个block都可以被继承它的子模板覆写,或者保留现在这种默认实现。该模板也能被直接输出。只不过此时只是显示基础模板所定义的内容,title, sidebarbody都将保持默认值。

一个子模板看起来是这样的:

1
2
3
4
5
6
7
8
9
10
11
{# 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 %}
1
2
3
4
5
6
7
8
9
10
11
<!-- 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() ?>

Note

父模板被存放在 app/Resources/views 目录,因此其路径是最简单的 base.html.twig。模板命名约定可参考下文的模板名称和位置

模板继承的关键字是 {% extends %} 标签。 该标签告诉模板引擎首先评估父模板,它设置了布局并定义了若干blocks。然后子模板被输出,上例中父模板中定义的 titlebody 两个blocks将会被子模板中的同名区块内容所取代。根据 blog_entries 的取值,输出的内容可能像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!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>

注意,由于子模板中没有定义 sidebar 这个block,来自父模板的内容将被显示出来。父模板中的 {% block %} 标签内的内容,始终作为默认值来用。

Tip

你可以进行任意多个层级的模板继承。Symfony项目中一般使用“三级继承”模式,来组织模板和页面,参考如何使用继承来组织你的Twig模板

使用模板继承时,需要注意:

  • 如果在模板中使用{% extends %},它必须是模板中的第一个标签。

  • 你的基础(布局)模板中的{% block %}标签越多越好,记得,子模板不必定义父模板中的所有block。基础模板中的block定义得愈多,你的布局就愈灵活。

  • 如果你发现在多个模板中有重复的内容,这可能意味着你需要为该内容在父模板中定义一个{% block %}了。某些情况下,更好的解决方案可能是把这些内容放到一个新模板中,然后在该模板中include它。(查看下文的:包容其他模板)

  • 如果你需要从父模板中获取一个block的内容,可以使用{{ parent() }}函数。如果你只是想在父级块上添加新内容,而不是完全覆盖它,这很有用:

1
2
3
4
5
6
7
{% block sidebar %}
    <h3>Table of Contents</h3>
 
    {# ... #}
 
    {{ parent() }}
{% endblock %}

模板的命名和存放位置 

默认情况下,模板可以存放在两个不同的位置:

app/Resources/views

程序级的views目录可以存放整个程序的基础模板(程序布局和bundle模板),以及那些“用于覆写第三方bundle的模板”的模板(如何覆写三方bundle的模板)。

path/to/bundle/Resources/views

每个第三方bundle的模板都会存放于它自己的 Resources/views/ 目录(或者子目录)下。当你打算共享你的bundle时,你应该把它放在bundle中,而不是app/目录。

更多时候你要用到的模板是在 app/Resources/views/ 目录下。你需要的模板路径是相对于这个目录的。例如,去输出/继承 app/Resources/views/base.html.twig,你需要使用 base.html.twig 的路径,而要输出 app/Resources/views/blog/index.html.twig 时,你需要使用 blog/index.html.twig 路径。

从Bundle中引入模板 

如果 你需要引入一个位于bundle中的模板,Symfony使用Twig命名空间之语法(@BundleName/directory/filename.html.twig)来表示。这可以表示多种类型的模板,每种都存放在一个特定路径下:

  • @AcmeBlog/Blog/index.html.twig:用于指定一个特定页面的模板。字符串分为三个部分,每个部分由冒号(/)隔开,含义如下:
  • @AcmeBlog: 这是去掉了 Bundle 后缀的bundle名称。这个模板位于 AcmeBlogBundle (即 src/Acme/BlogBundle) 中;
  • Blog: (目录) 指示了模板位于 Resources/views/Blog 子目录中;
  • index.html.twig: (文件名) 文件的真实名称是 index.html.twig

假设AcmeBlogBundle位于 src/Acme/BlogBundle, 最终的路径将是:src/Acme/BlogBundle/Resources/views/Blog/index.html.twig

  • @AcmeBlog/layout.html.twig:这种语法指向了 AcmeBlogBundle 的父模板。由于没有了中间的“目录”部分(即 blog),模板应该位于 AcmeBlogBundle 的 Resources/views/layout.html.twig

如何覆写第三方bundle的模板 一文中,你将了解到位于 AcmeBlogBundle 中的模板,是如何被 app/Resources/AcmeBlogBundle/views/ 目录下的同名模板所覆写的,这种方式给了我们一个有力的途径来覆写任何第三方bundle所提供的模板。

模版后缀 

每个模版都有两个扩展名,用来指定 格式(format)和模版 引擎(engine)。

文件名 Format 引擎
blog/index.html.twig HTML Twig
blog/index.html.php HTML PHP
blog/index.css.twig CSS Twig

默认情况下,Symfony的任何模板都可以被写成Twig或者PHP引擎的,它由后缀(.twig.php)来决定使用哪个引擎。其中后缀的前一部分(.html,.css)表示最终生成的格式。不像引擎,它是决定symfony如何解析模板,这是一个很简单的使用策略,你可以使用HTML(index.html.twig),XML(index.xml.twig)或任何其他格式作为输出的资源。参考如何在模版中使用不同的输出格式以了解更多。

Tags和Helpers 

你已经了解了模板基础,它们是如何命名的,以及如何使用模板继承等基础知识。最难的部分已经过去。接下来,我们将了解大量的可用工具,来帮我们完成常见的模板任务,比如包容其他模板,链接到一个页面或者引入图片。

Symfony框架中内置了几个特殊的Twig标签和功能函数,来帮助模板设计者简化工作。在PHP中,模板系统提供了一个可扩展的helper 系统用于在模板上下文中提供有用的功能。

你已经看到了一些内置的Twig标签,比如({% block %}{% extends %})等,还有PHP helper $view[‘slots’]。现在,你将会学到更多。

引入其他模版 

你经常需要在多个不同的页面中包含同一个模板或者代码片段。比如在一个“新闻文章”程序中,用于显示文章的模板代码可能会被用到正文页,或者用到一个显示“人气文章”的页面,乃至一个“最新文章”的列表页等。

当你需要复用一些PHP代码时,通常都是把这些代码放到一个PHP类或者函数中。同样在模板中你也可以这么做。通过把可复用的代码放到一个它自己的模板中,然后从其他模板中包容这个模板。首先,创建一个可复用模板如下:

1
2
3
4
5
6
7
{# app/Resources/views/article/article_details.html.twig #}
<h2>{{ article.title }}</h2>
<h3 class="byline">by {{ article.authorName }}</h3>
 
<p>
    {{ article.body }}
</p>
1
2
3
4
5
6
7
<!-- 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>

在其他任何模板中引入这个模板很简单:

1
2
3
4
5
6
7
8
9
10
{# 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 %}
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 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() }} 标签。注意,模板命名要遵循相同的典型约定。在 article_details.html.twig 模板中使用article 变量,这是我们传入模板的。本例中,你也可以完全不这样做,因为在 list.html.twig 模板中所有可用的变量也都可以在 article_details.html.twig 中使用(除非你设置with_context为false)。

Tip

{'article':article} 语法是标准Twig哈希映射(hash maps)的写法(即是一个键值对数组)。如果你需要传递多个元素,可以写成 {'foo': foo, 'bar': bar}

链接到页面 

在你的程序中创建一个链接到其他页面,对于模板来说是再普通不过的事情了。使用 path Twig函数(或者PHP中的router helper)基于路由配置来生成URL而非在模板中写死URL。以后,如果你想修改一个特定页面的链接,你只需要改变路由配置即可;模板将自动生成新的URL。

比如我们打算链接到“_welcome”页面,首先定义其路由配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/AppBundle/Controller/WelcomeController.php
 
// ...
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 
class WelcomeController extends Controller
{
    /**
     * @Route("/", name="_welcome")
     */
    public function indexAction()
    {
        // ...
    }
}
1
2
3
4
# app/config/routing.yml
_welcome:
    path:     /
    defaults: { _controller: AppBundle:Welcome:index }
1
2
3
4
5
6
7
8
9
10
11
<!-- 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>
1
2
3
4
5
6
7
8
9
10
// app/config/routing.php
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
 
$collection = new RouteCollection();
$collection->add('_welcome', new Route('/', array(
    '_controller' => 'AppBundle:Welcome:index',
)));
 
return $collection;

要链到页面,只需使用Twig的 path 函数来指定这个路由即可。

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

正如预期的那样,它生成了URL /。现在,处理一个更复杂的路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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)
    {
        // ...
    }
}
1
2
3
4
# app/config/routing.yml
article_show:
    path:     /article/{slug}
    defaults: { _controller: AppBundle:Article:show }
1
2
3
4
5
6
7
8
9
10
11
<!-- app/config/routing.xml -->
<?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="article_show" path="/article/{slug}">
        <default key="_controller">AppBundle:Article:show</default>
    </route>
</routes>
1
2
3
4
5
6
7
8
9
10
// app/config/routing.php
use 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;

这种情况下,你需要指定路由名称(article_show)以及一个 {slug} 参数。使用这个路由重新访问前面提到的 recent_list.html.twig 模板,即可正确地链接到文章。

1
2
3
4
5
6
{# app/Resources/views/article/recent_list.html.twig #}
{% for article in articles %}
    <a href="{{ path('article_show', {'slug': article.slug}) }}">
        {{ article.title }}
    </a>
{% endfor %}
1
2
3
4
5
6
7
8
<!-- 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 ?>

Tip

你可以通过Twig的 url 函数来生成绝对路径:

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

链接到Assets 

模板通常也需要一些图片,Javascript,样式文件和其他web资源。当然你可以写死它们的路径。比如 /images/logo.png。 但是Symfony通过Twig函数 asset(),提供了一个更加动态的选择,。

1
2
3
<img src="{{ asset('images/logo.png') }}" alt="Symfony!" />
 
<link href="{{ asset('css/blog.css') }}" rel="stylesheet" />
1
2
3
<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 函数的主要目的,是让你的程序更加portable(可移动)。如果你的程序在主机根目录下(如 http://example.com),生成的路径应该是 /images/logo.png 。但是如果你的程序位于一个子目录中(如 http://example.com/my_app),asset路径在生成时应该带有子目录(如 /my_app/images/logo.png)。asset函数负责打点这些,它根据你的程序 “是如何使用的” 而生成相应的正确路径。

Tip

asset() 函数通过 version, version_format, 以及 json_manifest_path 配置选项支持不同的“缓存击破”(cache busting)策略。

如果你需要assets资源的绝对URL,可以使用 absolute_url() Twig函数:

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

在Twig中包容样式表和Javascript 

每个网站中都不能完全没有样式表和javascript文件。在Symfony中,这些内容可以利用模板继承来优雅地处理。

Tip

本节教给你包容stylesheet和javaScript资源时的背后思想。Symfony支持另外一个类库叫Assetic, 它允许你在遵循这一思想时,对这些资源做更多有趣事情。参考如何使用Assetic 进行资产管理以了解更多细节。

首先在你的基础布局模板中添加两个blocks来保存你的资源,一个叫 stylesheets,放在 head 标签里,另一个叫 javascript,放在 body 结束标签上面一行。这些blocks将包含你整个站点所需的全部stylesheets和Javascripts。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{# 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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>

这也太简单了!但如果你想从子模板中包容一个额外的stylesheet或者javascript进来该怎么办呢?比如,假设你有一个联系页面需要包容一个 contact.css 样式表, 用在该页面上。在联系人页面的模板中,你可以这样实现:

1
2
3
4
5
6
7
8
9
10
{# app/Resources/views/contact/contact.html.twig #}
{% extends 'base.html.twig' %}
 
{% block stylesheets %}
    {{ parent() }}
 
    <link href="{{ asset('css/contact.css') }}" rel="stylesheet" />
{% endblock %}
 
{# ... #}
1
2
3
4
5
6
// 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并把你新的样式表标签放到该区块里。当然,由于你只是想把它添加到父块儿的内容中(而不是真的 替代 它们),所以你需要先用 parent() 函数来获取基础模板中的所有 stylesheets 区块中的内容。

你也可以包容位于你bundle的 Resources/public 文件夹下的assets资源。你需要运行 php bin/console assets:install target [–symlink]命令,它会把文件移动到(或symlink到)正确的位置(默认目标位置是“web”文件夹)。

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

最终结果是,页面中同时包容了main.csscontact.css两个样式表。

引用Request,User或Session对象 

Symfony在Twig中给了你一个全局的 app 变量,可以用于访问当前用户、请求以及更多对象。

参考 如何在Twig中通过app变量访问到User, Request, Session和更多对象 以了解细节。

输出转义 

在输出任意内容时,Twig自动进行“输出转义(output escaping)”,为的是保护你免受 Cross Site Scripting (XSS)跨站攻击。

假设 descriptionI <3 this product

1
2
3
4
5
<!-- output escaping is on automatically / 自动开启了输出转义 -->
{{ description }} <!-- I &lt3 this product -->
 
<!-- disable output escaping with the raw filter / 使用raw调节器关闭了输出转义 -->
{{ description|raw }} <!-- I <3 this product -->

Caution

PHP模板不对内容进行自动转义。

更多细节,参考 如何对模板输出进行转义

总结 

模板系统 仅仅 是Symfony诸多工具中的一个。它的工作很简单:让我们渲染动态的、复杂的HTML输出,它们最终被返回给用户,发送到一封邮件或其他什么东西之中。

Keep Going! 

深入Symfony其余部分之前,先看一下 configuration配置系统

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)