Symfony2学习笔记之模板用法详解

本文实例讲述了Symfony2学习笔记之模板用法分享给大家供大家参考,具体如下:

我们知道,controller负责处理每一个进入Symfony2应用程序的请求。实际上,controller把大部分的繁重工作都委托给了其它地方,以使代码能够被测试和重用。当一个controller需要生成HTML,CSS或者其他内容时,它把这些工作给了一个模板化引擎。

模板:

一个模板仅仅是一个文本文件,它能生成任意的文本格式(HTML,XML,CSV,LaTex...)。最著名的模板类型就是PHP模板了,可以被PHP解析的文本文件,它混合了文本和PHP代码

rush:PHP;"> Welcome to Symfony!

但是Symfony2包中拥有一种更加强大的模板化语言叫Twig。 它允许你写简洁,可读法模板语言。对页面设计师更友好,在许多方面比PHP模板更加强大。

rush:PHP;"> Welcome to Symfony!

{{ page_title }}

在这个Twig文件中,定义了三个类型的特别语法

Twig也包含filters,在渲染之前修改内容。下面的语句显示把title变量全部渲染为大型。

Twig默认情况下有一大群的标签(tags)和过滤器(filters)可以使用。当然你也可以根据需要添加扩展。注册一个Twig扩展非常容易,创建一个新服务并把它标记为Twig.extension 标签。就跟你看到的一样,Twig也支持功能和新功能的添加。比如,下面使用一个标准的for标签和cycle功能函数来打印10个div 标签,用odd,even 类代替。

{% emdfor %}

Twig模板缓存

Twig很快。 每个Twig模板被编译到原生的PHP类,它将在运行时被渲染。编译过的类被保存在app/cache/{environment}/twig 目录下并在某些情况下,对整个调试非常有用。当debug模式可用时,一个twig模板如果发生改变将会被自动重新编译。这就意味着你可以在开发过程中随意的修改模板,而不必担心需要去清除内存了。当debug模式被关闭时,你必须手动的清除Twig缓存目录,以便能够重新生成Twig模板。

模板继承和布局

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

现在首先创建一个base layout文件:

Twig:

{% block title %}Test Application{% endblock %}

PHP代码格式:

这个模板定义了基本的HTML初始文档是一个简单的两列式页面。在这个页面中有三处{% block %}定义,分别定义了title,sidebar和body。每个block都可以被继承它的子模板重写或者保留它现在的默认实现。该模板也能被直接渲染,只不过只是显示基础模板的定义内容。

下面定义一个子模板:

Twig格式:

{{ entry.title }}

{{ entry.body }}

{% endfor %} {% endblock %}

PHP代码格式:

extend('::base.html.php') ?> set('title','My cool blog posts') ?> start('body') ?>

getTitle() ?>

getBody() ?>

stop() ?>

父模板被一个特殊的字符串语法表示 ::base.html.twig,它表示该模板在项目的 app/Resources/views 目录下。

模板继承的关键字 {% extends %}标签。 该标签告诉模板化引擎首先评估父模板,它会设置布局和定义多个blocks。然后是子模板,上例中父模板中定义的title和body 两个blocks将会被子模板中的定义所取代。依靠blog_entries的值,输出的内容如下:

在此我们注意到,因为子模板中没有定义sidebar这个block,所以来自父模板的内容被显示出来,而没有被子模板替代。位于父模板中的{% block %}标签是默认值,如果没有被子模板重写覆盖,它将作为默认值使用。

你可以根据你的需要进行多层继承。 Symfony2项目中一般使用一种三层继承模式来组织模板和页面。当我们使用模板继承时,需要注意:

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

你基础模板中{% block %}越多越好,记住,子模板不必等一父模板中所有的block。你父模板中block定义的越多,你的布局就越灵活。

如果你发现在多个模板中有重复的内容,这可能就意味着你需要为该内容在父模板中定义一个{% block %}。有些时候更好的解决方案可能是把这些内容放到一个新模板中,然后在该模板中include它。

如果你需要从父模板中获取一个block的内容,你可以使用{{ parent() }}函数。

Table of Contents ... {{ parent() }} {% endblock %}

模板的命名和存储位置

默认情况下,模板可以被保存到两个位置:

Symfony2使用bundle:controller:template 字符串语法表示模板。这可以表示许多不同类型的模板,每种都存放在特定的路径下: AcmeBlogBundle:Blog:index.html.twig 用于指定一个特定页面的模板。 AcmeBlogBundle 表示bundle,说明模板位于AcmeBlogBundle,比如src/Acme/BlogBundle。 Blog 表示BlogController,指定模板位于Resourcs/views的Blog子目录中,index.html.twig为模板名字。

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

AcmeBlogBundle::layout.html.twig 该表示法指向AcmeBlogBundle的基模板。没有controller部分,所以模板应该位于AcmeBlogBundle的Resources/views/layout.html.twig

::base.html.twig 表示一个应用程序级的基模板或者布局文件。注意,该语句两个冒号开头,意味着没有bundle和controller部分,这说明该文件不在某个bundle中,而是位于根目录下 app/Resources/views

在重写Bundle模板一节,你将发现位于AcmeBlogBundle的模板是如何被位于app/Resources/AcmeBlogBundle/views/目录下的所有模板同名重写的, 这种方式给了我们一个有力的途径来重写供应商提供的bundle的模板。

模板后缀(suffix)

bundle:controller:template 句法说明了每个模板文件的存放位置。每个模板名字也有两个扩展名来指定格式和模板引擎。 AcmeBlogBundle:Blog:index.html.twig HTML格式,Twig引擎 AcmeBlogBundle:Blog:index.html.php HTML格式,PHP引擎 AcmeBlogBundle:Blog:index.css.twig CSS格式,Twig引擎 默认情况下,Symfony2的任何模板都可以被写成Twig或者PHP引擎的,它由后缀决定。其中后缀的前一部分(.html,.css)表示最终生成的格式。

标签和助手类

你已经基本了解了模板,它们如何命名如何使用模板继承等。最难理解的部分已经过去。接下来我们将了解大量的可用工具来帮助我们执行最通用的模板任务比如包含另外一个模板,链接一个页面或者包含一个图片等。

Symfony2 中包含了血多序列化的Twig标签和功能函数来帮助设计者更容易的完成工作。在PHP中,模板系统提供了一个可扩展的helper系统,它可以在模板上下文中提供许多有用的内容。我们已经看过一些内建的Twig标签,比如{% block %}{% extends %}等,还有PHP 助手$view['slots']。

包含其它模板:

你可能经常想在多个不同的页面中包含同一个模板或者代码片段。比如一个应用程序中有"新闻文章",模板代码在显示一片文章时可能用到文章详细页面,一个现实最流行文章的页面,或者一个最新文章的列表页面等。

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

Twig格式:

{{ article.title }}

PHP代码格式:

getTitle() ?>

getBody() ?>

然后我们把它包含到其它模板定义中:

Twig格式:

Recent Articles

{% for article in articles %} {% include 'AcmeArticleBundle:Article:articleDetails.html.twig' with {'article': article} %} {% endfor %} {% endblock %}

PHP代码格式:

extend('AcmeArticleBundle::layout.html.php') ?> start('body') ?>

Recent Articles

render('AcmeArticleBundle:Article:articleDetails.html.php',array('article' => $article)) ?> stop() ?>

模板的包含使用{% include %}标签。模板的名称要使用通用方式。在articleDetails.html.twig模板中使用article变量,这里通过在list.html.twig模板中使用with命令传入。{'article':article}语法是标准Twig哈希映射的写法。如果我们需要传递多个元素,可以写成{'foo': foo,'bar': bar}。

嵌入Controllers

有些情况下,你需要比包含简单模板做到更多。假设你有一个菜单栏sidebar在你的布局文件中来显示最新的文章。获取三篇最新文章可能需要查询数据库或者执行其它包含很多逻辑的操作,这样就不能在一个模板中进行了。这种情况的解决方案是简答键入一个完整的controller到你的模板。首先创建一个controller来渲染特定数量的最近文章:

render('AcmeArticleBundle:Article:recentList.html.twig',array('articles'=>articles)); } }

而recentList模板则相当简单:

Twig格式:

{% endfor %}

PHP代码格式:

为了能包含controller,你需要使用一个标准的字符语法来表示controller,格式类似bundle:controller:action

Twig格式:

rush:PHP;"> {# app/Resources/views/base.html.twig #} ...

PHP代码格式:

rush:PHP;"> ...

无论什么时候,你需要一个变量或者一些列信息时,你不必在模板中访问,而是考虑渲染一个controller。因为Controller能够更快的执行并且很好的提高了代码的组织和重用。

链接页面

在你的应用程序中创建一个链接到其它页面对于一个模板来说是再普通不过的事情了。我们采用path Twig函数基于路由配置来生成URL而非在模板中硬编码URL。以后如果你想修改一个特定页面的URL,你只需要改变路由配置即可,模板将自动生成新的URL。比如我们打算链接到"_welcome"页面,首先定义其路由配置:

YAML格式:

rush:xhtml;"> _welcome: pattern: / defaults: { _controller: AcmeDemoBundle:Welcome:index }

XML格式:

rush:PHP;"> cmeDemoBundle:Welcome:index

PHP代码格式:

add('_welcome',new Route('/',array( '_controller' => 'AcmeDemoBundle:Welcome:index',))); return $collection;

我们可以在模板中使用Twig函数 path来引用这个路由链接页面

Twig格式:

rush:PHP;">

PHP代码格式:

上面的内容生成一个URL /

我们看另一个复杂一些的路由定义:

YAML格式:

rush:PHP;"> article_show: pattern: /article/{slug} defaults: { _controller: AcmeArticleBundle:Article:show }

XML格式:

rush:xml;"> cmeArticleBundle:Article:show

PHP代码格式:

add('article_show',new Route('/article/{slug}',array( '_controller' => 'AcmeArticleBundle:Article:show',))); return $collection;

这种情况下你需要指定路由名称(article_show)还要一个参数值{slug}。现在让我们再来看上面的recentList模板 ,我们修改以前的硬编码而使用path来链接正确的文章

Twig格式:

rush:PHP;"> {# src/Acme/ArticleBundle/Resources/views/Article/recentList.html.twig #} {% for article in articles %} {% endfor %}

PHP代码格式:

你也可以通过url Twig函数生成一个绝对路径的URL:

rush:PHP;">

在PHP代码模板中,你需要给generate()方法传入第三个参数true 来实现生成绝对路径URL

链接到资源

模板通常也需要一些图片,Javascript,样式文件和其它资产。当然你可以硬编码它们的路径。比如/images/logo.png。 但是Symfony2 提供了一个更加动态的Twig函数 asset()。

Twig格式:

rush:PHP;"> Symfony!

PHP代码格式:

rush:PHP;"> logo.png') ?>" alt="Symfony!" />

asset函数的主要墨笔是让你的应用程序更加轻便。如果你的应用程序在你的主机根目录下(比如:http://example.com),那么它会渲染出的路径为 /images/logo.png 。但是如果你的应用程序位于一个子目录中(比如:http://example.com/my_app),这时它会为你渲染出的路径变为 /my_app/images/logo.png 。asset函数能够根据你的应用程序来生成正确的路径。

另外,如果你使用asset函数,symfony可以自动追加一个查询字符串到你的资产,以保证被更新的静态资源不会在部署时被缓存。比如:/images/logo.png 可能看起来是 /images/logo.png?v2 。

包含样式表和Javascript文件到Twig模板:

每个网站中都不可能缺少了样式表和javascript文件。在Symfony中,这些内容可以通过模板继承很好的进行包含处理。Symfony打包了另外一个类库叫做Assetic,它允许你对这些资源做更多的有趣操作。首先在你的基模板中添加两个blocks来保存你的资源,一个叫stylesheets,放在head标签里,另一个叫javascript,放在body结束标签上面一行。这些blocks将包含你整个站点所需要的所有stylesheets和javascripts。

rush:PHP;"> {# 'app/Resources/views/base.html.twig' #} {# ... #} {% block stylesheets %} {% endblock %} {# ... #} {% block javascripts %}

没有任何的输出安全转义,结果模板会触发JavaScript弹出框:

rush:js;"> Hello

这种情况看上去,没多大害处,如果一个用户知道这一步,它完全有能力写一个javascript在我们未知的安全区域来执行一些恶意行为。这个问题的解决办法是输出安全转义。 如果添加输出安全转义,同样的模板会渲染出无害的内容,script标签会作为普通文本输出到屏幕上。

rush:xhtml;"> Hello

PHP和Twig模板化系统采用了不同的方式来解决这个问题。如果你使用Twig,认情况下是输出安全转义的,你的输出是受到保护的。如果是PHP,则输出安全转义不是自动的,需要你手工的进行处理。

Twig中的安全输出

如果你使用Twig模板,那么输出安全是认的。你不需要对用户提交的输出内容进行手动保护。在某些情况下,你需要关闭输出安全保护,当你渲染某个可信变量或者包含某个标签时。假设管理员用户可以编写一些代码有HTML标签文章认情况下,Twig将转义文章体。为了渲染正常,需要添加一个raw 过滤器:

rush:PHP;"> {{article.body | raw }}

你也可以在{% block %}区域或者整个模板中关闭安全保护。

PHP中的安全输出保护:

PHP中安全输出保护不是自动完成的,这就意味着除非你显示的选择来对某个输出变量进行保护,否则输出都是不安全的。我们使用view的方法escape()来对输出变量进行安全输出保护:

rush:PHP;"> Hello escape($name) ?>

认情况下,escape()方法认情况下假设变量是被渲染在一个HTML上下文中的。也就是说只针对HTML安全。 它的第二个参数让你能够改变它针对的上下文。

比如需要在javascript上下文中输出某些东西,就是用 js 上下文。

rush:PHP;"> var myMsg = 'Hello escape($name,'js') ?>';

模板调试

当使用PHP代码时,我们可以使用var_dump()来快速的查看一个值的变量传递。同样在Twig中,我们可以使用debug扩展来达到相同的效果,只是需要预先在配置文件中开启。

YAML 格式:

rush:xhtml;"> # app/config/config.yml services: acme_hello.twig.extension.debug: class: Twig_Extension_Debug tags: - { name: 'twig.extension' }

XML格式:

rush:xml;"> cme_hello.twig.extension.debug" class="Twig_Extension_Debug">

PHP代码格式:

addTag('twig.extension'); $container->setDeFinition('acme_hello.twig.extension.debug',$deFinition);

这时候,我们就可以使用dump函数来查看模板参数了:

rush:PHP;"> {# src/Acme/ArticleBundle/Resources/views/Article/recentList.html.twig #} {{ dump(articles) }} {% for article in articles %} {% endfor %}

模板格式:

模板是一个渲染任何格式内容的通用的方式。大多数情况下,我们使用模板来渲染HTML内容。模板同样也能渲染想javascript,CSS,XML以及你能想象到的其它格式内容。比如,同一个资源resource经常被渲染为不同的格式。把文章目录页渲染为XML,你需要在模板的名称中包含相应的格式即可。

XML 模板名: AcmeArticleBundle:Article:index.xml.twig XML 模板文件名:index.xml.twig

事实上,这里只是命名上有了变化,而模板并没有真正的基于不同的格式渲染不同。在大多数情况下,你可能想让单一的controller根据请求的格式不同渲染多个不同的格式。下面是一个通常的写法:

getRequest()->getRequestFormat(); return $this->render('AcmeBlogBundle:Blog:index.'.$format.'.twig'); }

Request对象的getRequestFormat()方法默认返回值为html,request的格式通常是在路由时决定的。比如/contact 设置的请求格式是html,而 /contact.xml 设置的请求格式则是 XML。创建一个包含请求格式的链接,只需要在参数哈希表中包含 _format键值即可。

Twig格式:

PHP代码格式:

rush:PHP;">

总结思考:

Symfony2中的模板引擎是一个强大的工具,你可以用它来根据需要生成包括HTML,XML以及其它任何格式的内容。尽管模板时controller生成内容的通常方式,但是不是必须的。controller返回的Response对象可以使用模板也可以没有模板。

render('AcmeArticleBundle:Article:index.html.twig'); // 使用简单文本内容生成Response对象 $response = new Response('response content');

Symfony2的模板引起非诚灵活,认情况下支持传统的PHP模板和圆滑强大的Twig模板,他们都拥有非常丰富的帮助函数来执行一些常见任务,Symfony2推荐使用Twig模板,因为它更加简洁,高效,能更好的处理继承等。

希望本文所述对大家基于Symfony框架的PHP程序设计有所帮助。

相关文章

统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
前言 之前做了微信登录,所以总结一下微信授权登录并获取用户...
FastAdmin是我第一个接触的后台管理系统框架。FastAdmin是一...
之前公司需要一个内部的通讯软件,就叫我做一个。通讯软件嘛...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...