創(chuàng)建和使用模板
<img src="{{ absolute_url(asset('images/logo.png')) }}" alt="Symfony!" />
就像你知道的,控制器(controller)負(fù)責(zé)處理每一個(gè)進(jìn)入symfony程序的請(qǐng)求。實(shí)際上,控制器把大部分的繁重工作都委托給了其他地方,以令代碼能夠被測(cè)試和復(fù)用。當(dāng)一個(gè)controller需要生成HTML、CSS或者其他內(nèi)容時(shí),它把這些工作給了一個(gè)模板引擎。在本章中,你將學(xué)習(xí)如何編寫功能強(qiáng)大的模板,用于把內(nèi)容返回給用戶、填充email,等等。你還將學(xué)會(huì)快捷方法,用巧妙的方法擴(kuò)展模板,以及如何復(fù)用模板代碼。
如何渲染模板請(qǐng)查看“框架起步”之控制器。
模板 ?
模板就是生成基于文本格式(html,xml,csv,LaTex…)的任何文本文件。我們最熟悉的模板類型就是php 模板——包含文字和php代碼的被PHP引擎解析的文本文件:
<!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 框架中有一個(gè)更強(qiáng)大的模板語(yǔ)言叫作Twig。Twig可令你寫出簡(jiǎn)明易讀且對(duì)設(shè)計(jì)師友好的模板,在幾個(gè)方面比PHP模板強(qiáng)大許多。
<!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定義了三種特殊的語(yǔ)法:
{{ ... }}
- “說(shuō)些什么”:輸出一個(gè)變量值或者一個(gè)表達(dá)式的結(jié)果到模板。
{% ... %}
- “做些什么”:控制模板邏輯的*tag(標(biāo)簽)*,用于執(zhí)行聲明,如for循環(huán)語(yǔ)句等。
{# ... #}
- “進(jìn)行注釋”:它相當(dāng)于php的
/* comment */
語(yǔ)法。它用于注釋單行和多行。注釋的內(nèi)容不作為頁(yè)面輸出。
twig也包含filters,它可以在模板渲染之前改變輸出內(nèi)容。下例讓title變量在被渲染之前全部大寫:
{{ title|upper }}
Twig內(nèi)置了大量的標(biāo)簽(tags)和變量調(diào)節(jié)器(filters),默認(rèn)就可以使用。你甚至可以利用Twig擴(kuò)展來(lái)添加你自己的自定義 調(diào)節(jié)器和函數(shù)(乃至更多)。
注冊(cè)一個(gè)Twig擴(kuò)展非常容易,創(chuàng)建一個(gè)新服務(wù)并打上Twig.extension
標(biāo)簽。
Twig代碼很像PHP代碼,兩者有微妙的區(qū)別。下例使用了一個(gè)標(biāo)準(zhǔn)的for
標(biāo)簽和cycle
函數(shù)來(lái)輸出10個(gè)div 標(biāo)簽,用odd
、even
css類交替顯示。
{% for i in 0..10 %} <div class="{{ cycle(['odd', 'even'], i) }}"> <!-- some HTML here --> </div>{% endfor %}
本章的模板例程,將同時(shí)使用twig和php來(lái)展示。
如果你不使用Twig或者禁用它,你需要使用kernel.execption
事件來(lái)實(shí)現(xiàn)一個(gè)你自己的異常處理。
Twig模板緩存 ?
twig是很快的,每個(gè)Twig模板被編譯成原生PHP類并且緩存起來(lái)。編譯過(guò)的類被保存在var/cache/{environment}/twig
目錄下(其中{environment}
是環(huán)境,如dev
和prod
),并在某些情況下可以同時(shí)調(diào)試,非常有用。關(guān)于環(huán)境的更多細(xì)節(jié)請(qǐng)參考:環(huán)境
當(dāng)debug
模式可用時(shí)(dev
環(huán)境),如果一個(gè)twig模板發(fā)生改變,將會(huì)被自動(dòng)重新編譯。這意味著你可以在開發(fā)過(guò)程中隨意修改模板,而不必?fù)?dān)心要去清除緩存了。
當(dāng)debug
模式被關(guān)閉時(shí)(prod
環(huán)境),你必須手動(dòng)的清除Twig緩存目錄,以便重新生成Twig模板。記得在部署程序時(shí)一定要做到這一點(diǎn)。
模板繼承和布局 ?
大多數(shù)的時(shí)候,模板在項(xiàng)目中都有通用的元素,比如header,footer,sidebar等等。在Symfony中,我們將采用不同的思考角度來(lái)對(duì)待這個(gè)問(wèn)題。一個(gè)模板可以被另外的模板裝飾。這個(gè)的工作原理跟PHP類非常像,模板繼承讓你可以創(chuàng)建一個(gè)基礎(chǔ)“l(fā)ayout”模板,它包含你的站點(diǎn)所有通用元素,并被定義成blocks(如同一個(gè)“包含基礎(chǔ)方法的PHP基類”)。一個(gè)子模板可以繼承l(wèi)ayout基礎(chǔ)模板并覆寫它的任何一個(gè)block(就像“PHP子類覆寫父類中的特定方法”)。
首先創(chuàng)建一個(gè)layout基礎(chǔ)文件:
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>
雖然討論的是關(guān)于Twig的模板繼承,但在思維方式上twig和php模板之間是相同的。
該模板定義了一個(gè)簡(jiǎn)單的兩列式html頁(yè)面。在本例中,三處 {% block %}
區(qū)域被定義了(即title
,sidebar
和body
)。每個(gè)block都可以被繼承它的子模板覆寫,或者保留現(xiàn)在這種默認(rèn)實(shí)現(xiàn)。該模板也能被直接渲染(輸出)。只不過(guò)此時(shí)只是顯示基礎(chǔ)模板所定義的內(nèi)容,title
, sidebar
和 body
都將保持默認(rèn)值。
一個(gè)子模板看起來(lái)是這樣的:
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() ?>
父模板以一個(gè)特殊的字符串語(yǔ)法來(lái)表示 base.html.twig
,這個(gè)路徑是相對(duì)于整個(gè)項(xiàng)目的app/Resources/views
目錄而言的。你也可以使用邏輯名稱相同的::base.html.twig
。參考下文的模板名稱和位置。
模板繼承的關(guān)鍵字是 {% extends %}
標(biāo)簽。 該標(biāo)簽告訴模板引擎首先評(píng)估父模板,它設(shè)置了布局并定義了若干blocks。然后子模板被渲染,上例中父模板中定義的title
和body
兩個(gè)blocks將會(huì)被子模板中的同名區(qū)塊內(nèi)容所取代。根據(jù)blog_entries
的取值,輸出的內(nèi)容可能像下面這樣:
<!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>
注意,由于子模板中沒(méi)有定義sidebar
這個(gè)block,來(lái)自父模板的內(nèi)容將被顯示出來(lái)。父模板中的{% block %}
標(biāo)簽內(nèi)的內(nèi)容,始終作為默認(rèn)值來(lái)用。
你可以進(jìn)行任意多個(gè)層級(jí)的模板繼承。Symfony項(xiàng)目中一般使用“三級(jí)繼承”模式,來(lái)組織模板和頁(yè)面,參考如何使用繼承來(lái)組織你的Twig模板。
使用模板繼承時(shí),需要注意:
如果在模板中使用
{% extends %}
,它必須是模板中的第一個(gè)標(biāo)簽。你的基礎(chǔ)(布局)模板中的
{% block %}
標(biāo)簽越多越好,記得,子模板不必定義父模板中的所有block?;A(chǔ)模板中的block定義得愈多,你的布局就愈靈活。如果你發(fā)現(xiàn)在多個(gè)模板中有重復(fù)的內(nèi)容,這可能意味著你需要為該內(nèi)容在父模板中定義一個(gè)
{% block %}
了。某些情況下,更好的解決方案可能是把這些內(nèi)容放到一個(gè)新模板中,然后在該模板中include
它。(查看下文的:包容其他模板)如果你需要從父模板中獲取一個(gè)block的內(nèi)容,可以使用
{{ parent() }}
函數(shù)。如果你只是想在父級(jí)塊上添加新內(nèi)容,而不是完全覆蓋它,這很有用:
{% block sidebar %} <h3>Table of Contents</h3> {# ... #} {{ parent() }}{% endblock %}
模板的命名和存儲(chǔ)位置 ?
默認(rèn)情況下,模板可以存放在兩個(gè)不同的位置:
app/Resources/views
程序級(jí)的views目錄可以存放整個(gè)程序的基礎(chǔ)模板(程序布局和bundle模板),以及那些“用于覆寫第三方bundle的模板”的模板(如何覆寫第三方bundle的模板)。
path/to/bundle/Resources/views
每個(gè)第三方bundle的模板都會(huì)存放于它自己的Resources/views/
目錄(或者子目錄)下。當(dāng)你打算共享你的bundle時(shí),你應(yīng)該把它放在bundle中,而不是app/
目錄。
更多時(shí)候你要用到的模板是在app/Resources/views/
目錄下。你需要的模板路徑是相對(duì)于這個(gè)目錄的。例如,去渲染/繼承app/Resources/views/base.html.twig
,你需要使用base.html.twig
的路徑,而要去渲染app/Resources/views/blog/index.html.twig
時(shí),你需要使用blog/index.html.twig
路徑。
在Bundle中引入模板 ?
Symfony使用bundle:directory:filename
字符串語(yǔ)法表示模板。這可以表示許多不同類型的模板,每種都存放在一個(gè)特定路徑下:
AcmeBlogBundle:Blog:index.html.twig
用于指定一個(gè)特定頁(yè)面的模板。字符串分為三個(gè)部分,每個(gè)部分由冒號(hào)(:
)隔開,含義如下:
AcmeBlogBundle
:(bundle)模板位于AcmeBlogBundle,比如src/Acme/BlogBundle
;Blog
:(目錄)表明模板位于Resourcs/views
的Blog
子目錄中;index.html.twig
:(文件名)文件的實(shí)際名稱為index.html.twig
。
假設(shè)AcmeBlogBundle位于src/Acme/BlogBundle
, 最終的路徑將是:src/Acme/BlogBundle/Resources/views/Blog/index.html.twig
AcmeBlogBundle::layout.html.twig
這種語(yǔ)法指向了AcmeBlogBundle的父模板。沒(méi)有了中間的“目錄”部分(如blog
),模板應(yīng)該位于AcmeBlogBundle的Resources/views/layout.html.twig
。是的,中間的兩個(gè)冒號(hào)意味著“控制器”子目錄部分被忽略了。
在如何覆寫第三方bundle的模板一文中,你將了解到位于AcmeBlogBundle的模板,是如何被app/Resources/AcmeBlogBundle/views/
目錄下的同名模板所覆寫的,這種方式給了我們一個(gè)有力的途徑來(lái)覆寫bundle作者提供的bundle模板。
模版的命名語(yǔ)法可能看上去比較熟悉——它類似于控制器命名模式中提到的約定。
模版后綴 ?
每個(gè)模版都有兩個(gè)擴(kuò)展名,用來(lái)指定格式(format) 和模版引擎(engine)。
文件名 | Format | 引擎 |
---|---|---|
blog/index.html.twig | HTML | Twig |
blog/index.html.php | HTML | PHP |
blog/index.css.twig | CSS | Twig |
默認(rèn)情況下,Symfony的任何模板都可以被寫成Twig或者PHP引擎的,它由后綴(.twig
或 .php
)來(lái)決定使用哪個(gè)引擎。其中后綴的前一部分(.html
,.css
)表示最終生成的格式。不像引擎,它是決定symfony如何解析模板,這是一個(gè)很簡(jiǎn)單的使用策略,你可以使用HTML(index.html.twig
),XML(index.xml.twig
)或任何其他格式作為渲染的資源。更多的細(xì)節(jié),請(qǐng)閱讀模版格式部分。
可用的“engines”部分是可配置的,甚至可以添加一個(gè)新的引擎。請(qǐng)查看 如何配置和使用模板服務(wù)以了解更多細(xì)節(jié)。
Tags和Helps ?
你已經(jīng)了解了模板基礎(chǔ),它們是如何命名以及如何使用模板繼承等基礎(chǔ)知識(shí)。最難的部分已經(jīng)過(guò)去。接下來(lái),我們將了解大量的可用工具來(lái)幫我們完成常見的模板任務(wù),比如包容其他模板,鏈接到一個(gè)頁(yè)面或者引入圖片。
Symfony框架中內(nèi)置了幾個(gè)特殊的Twig標(biāo)簽和功能函數(shù),來(lái)幫助模板設(shè)計(jì)者簡(jiǎn)化工作。在PHP中,模板系統(tǒng)提供了一個(gè)可擴(kuò)展的helper 系統(tǒng)用于在模板上下文中提供有用的功能。
你已經(jīng)看到了一些內(nèi)置的Twig標(biāo)簽,比如({% block %}
& {% extends %}
)等,還有PHP helper $view[‘slots’]
。現(xiàn)在,你將會(huì)學(xué)到更多。
引入其他模版 ?
你經(jīng)常需要在多個(gè)不同的頁(yè)面中包含同一個(gè)模板或者代碼片段。比如在一個(gè)“新聞文章”程序中,用于顯示文章的模板代碼可能會(huì)被用到正文頁(yè),或者用到一個(gè)顯示“人氣文章”的頁(yè)面,乃至一個(gè)“最新文章”的列表頁(yè)等。
當(dāng)你需要復(fù)用一些PHP代碼時(shí),你通常都是把這些代碼放到一個(gè)PHP類或者函數(shù)中。同樣在模板中你也可以這么做。通過(guò)把可復(fù)用的代碼放到一個(gè)它自己的模板中,然后從其他模板中包容這個(gè)模板。首先,創(chuàng)建一個(gè)可復(fù)用模板如下:
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>
在其他任何模板中引入這個(gè)模板很簡(jiǎn)單:
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() ?>
這個(gè)模板被包容時(shí),使用了{{ include() }}
標(biāo)簽。請(qǐng)注意,模板命名要遵循相同的典型約定。在article_details.html.twig
模板中使用article
變量,這是我們傳入模板的。本例中,你也可以完全不這樣做,因?yàn)樵?code>list.html.twig模板中可用的所有變量也都可以在article_details.html.twig
中使用(除非你設(shè)置with_context為false)。
{'article':article}
語(yǔ)法是標(biāo)準(zhǔn)Twig哈希映射(hash maps)的寫法(即是一個(gè)鍵值對(duì)數(shù)組)。如果你需要傳遞多個(gè)元素,可以寫成{'foo': foo, 'bar': bar}
。
鏈接到頁(yè)面 ?
在你的程序中創(chuàng)建一個(gè)鏈接到其他頁(yè)面,對(duì)于模板來(lái)說(shuō)是再普通不過(guò)的事情了。使用path
Twig函數(shù)(或者php中的router
helper)基于路由配置來(lái)生成URLs而非在模板中寫死URLs。以后,如果你想修改一個(gè)特定頁(yè)面的URL,你只需要改變路由配置即可;模板將自動(dòng)生成新的URL。
比如我們打算鏈接到“_welcome”頁(yè)面,首先定義其路由配置:
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;
要鏈到頁(yè)面,只需使用Twig的path
函數(shù)來(lái)指定這個(gè)路由即可。
Twig:<a href="{{ path('_welcome') }}">Home</a>
php:<a href="<?php echo $view['router']->path('_welcome') ?>">Home</a>
正如預(yù)期的那樣,它生成了URL /
。現(xiàn)在,處理一個(gè)更復(fù)雜的路由:
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>
這種情況下,你需要指定路由名稱()以及一個(gè)。使用這個(gè)路由重新定義前文提到的模板,并正確鏈入文章。
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 ?>
你可以通過(guò)Twig的url
函數(shù)來(lái)生成絕對(duì)路徑:
Twig:<a href="{{ url('_welcome') }}">Home</a> php:<a href="<?php echo $view['router']->url( '_welcome', array()) ?>">Home</a>
鏈接到Assets ?
模板通常也需要一些圖片,Javascript,樣式文件和其他web資產(chǎn)。當(dāng)然你可以寫死它們的路徑。比如 /images/logo.png
。 但是Symfony通過(guò)Twig函數(shù) asset()
,提供了一個(gè)更加動(dòng)態(tài)的選擇,。
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
函數(shù)的主要目的,是讓你的程序更加portable(可移動(dòng))。如果你的程序在主機(jī)根目錄下(如http://example.com
),生成的路徑應(yīng)該是 /images/logo.png
。但是如果你的程序位于一個(gè)子目錄中(如http://example.com/my_app
),asset路徑在生成時(shí)應(yīng)該帶有子目錄(如 /my_app/images/logo.png
) 。asset
函數(shù)負(fù)責(zé)打點(diǎn)這些,它根據(jù)你的程序 “是如何使用的” 而生成相應(yīng)的正確路徑。
另外,如果你使用asset
函數(shù),symfony可以自動(dòng)追加一個(gè)query string(查詢字符串)到你的資產(chǎn),以保證被更新的靜態(tài)資源不會(huì)在部署時(shí)被緩存。例如,/images/logo.png
可能看起來(lái)是 /images/logo.png?v2
。參考version配置一文以了解更多。
如果你需要assets資源的絕對(duì)URL,可以使用absolute_url()
Twig函數(shù):
<img src="{{ absolute_url(asset('images/logo.png')) }}" alt="Symfony!" />
在Twig中包容樣式表和Javascript ?
每個(gè)網(wǎng)站中都不能完全沒(méi)有樣式表和javascript文件。在Symfony中,這些內(nèi)容可以利用模板繼承來(lái)優(yōu)雅地處理。
本節(jié)教給你包容stylesheet和javaScript資源時(shí)的背后思想。Symfony支持另外一個(gè)類庫(kù)叫Assetic, 它允許你在遵循這一思想時(shí),對(duì)這些資源做更多有趣事情。參考如何使用Assetic 進(jìn)行資產(chǎn)管理以了解更多細(xì)節(jié)。
首先在你的基礎(chǔ)布局模板中添加兩個(gè)blocks來(lái)保存你的資源,一個(gè)叫stylesheets
,放在head
標(biāo)簽里,另一個(gè)叫javascript
,放在body
結(jié)束標(biāo)簽上面一行。這些blocks將包含你整個(gè)站點(diǎn)所需的全部stylesheets和javascripts。
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>
這也太簡(jiǎn)單了!但如果你想從子模板中包容一個(gè)額外的stylesheet或者javascript進(jìn)來(lái)該怎么辦呢?比如,假設(shè)你有一個(gè)聯(lián)系頁(yè)面需要包容一個(gè)contact.css
樣式表,僅 用在該頁(yè)面上。在聯(lián)系人頁(yè)面的模板中,你可以這樣實(shí)現(xiàn):
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并把你新的樣式表標(biāo)簽放到該區(qū)塊里。當(dāng)然,由于你只是想把它添加到父塊兒的內(nèi)容中(而不是真的替代它們),所以你需要先用parent()
函數(shù)來(lái)獲取基礎(chǔ)模板中的所有stylesheets
區(qū)塊中的內(nèi)容。
你也可以包容位于你bundle的Resources/public
文件夾下的assets資源。你需要運(yùn)行php bin/console assets:install target [–symlink]
命令,它會(huì)把文件移動(dòng)到(或symlink到)正確的位置(默認(rèn)目標(biāo)位置是“web”文件夾)。
<link href="{{ asset('bundles/acmedemo/css/contact.css') }}" rel="stylesheet" />
最終結(jié)果是,頁(yè)面中同時(shí)包容了main.css
和contact.css
兩個(gè)樣式表。
引用Request,User或Session對(duì)象 ?
Symfony在Twig中給了你一個(gè)全局的app
變量,可以用于訪問(wèn)當(dāng)前用戶、請(qǐng)求以及更多對(duì)象。
參考如何在Twig中通過(guò)app變量訪問(wèn)到User, Request, Session和更多對(duì)象以了解細(xì)節(jié)。
輸出轉(zhuǎn)義 ?
在渲染任意內(nèi)容時(shí),Twig自動(dòng)進(jìn)行“輸出轉(zhuǎn)義(output escaping)”,為的是保護(hù)你免受 Cross Site Scripting (XSS)跨站攻擊。
假設(shè)description
是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 -->
PHP模板不對(duì)內(nèi)容進(jìn)行自動(dòng)轉(zhuǎn)義。
更多細(xì)節(jié),參考如何對(duì)模板輸出進(jìn)行轉(zhuǎn)義。
總結(jié) ?
Symfony中的模板引擎是一個(gè)強(qiáng)大的工具,你可以用它來(lái)根據(jù)需要生成包括HTML,XML以及其他任何格式的內(nèi)容。雖然模板以控制器生產(chǎn)出來(lái)是一種常見的方式,但是不是必須的??刂破鞣祷氐腞esponse對(duì)象可以使用模板也可以沒(méi)有模板。
// 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的模板引起非常靈活,默認(rèn)情況下支持傳統(tǒng)的PHP模板和圓滑強(qiáng)大的Twig模板,它們都擁有非常豐富的幫助函數(shù)來(lái)執(zhí)行一些常見任務(wù)。Symfony推薦使用Twig模板,因?yàn)樗雍?jiǎn)潔,高效,能更好的處理繼承等。
總體而言,在你處理模板問(wèn)題的時(shí)候,它是一個(gè)強(qiáng)大的工具。在某些情況下,你可能不需要渲染模板,在symfony中,這絕對(duì)是沒(méi)有問(wèn)題的。