[twig官方文件]為模版設計師而生的Twig(上)-Twig使用指南

listwebit發表於2015-06-30

掌握瞭如何安裝Twig模版引擎之後,接下里就要學習Twig的語法和語義,然後建立Twig模版。而本文的將花費較大的篇幅來介紹模板引擎的語法和語義,這對於模版設計師將會是非常有用的參考。由於本文的原文篇幅較長,所以就分成兩部分進行翻譯。本文為第一部分。本文的內容較多,主要包括Tiwg的IDEs 整合,變數,全域性變數,設定變數,過濾器,函式,命名引數,控制結構,註釋,包含模板等內容。

1. 概要
模板是一個簡單的文字檔案。它可以生成任何基於文字的格式(HTML、XML、CSV等)。它不具有特定副檔名,html或xml都OK。 模板中包含的變數或表示式,用來控制模板的邏輯。當模版被預處理時,它們會被替換為變數值。

下面是說明了一些基本要素的最小模板。稍後我們將介紹更多細節:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
    <head>
        <title>My Webpage</title>
    </head>
    <body>
        <ul id="navigation">
        {% for item in navigation %}
            <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
        {% endfor %}
        </ul>
 
        <h1>My Webpage</h1>
        {{ a_variable }}
    </body>
</html>

Twig有兩種型別的分隔符:{%…%}和{{…}}。第一個是用於執行諸如for迴圈的控制語句,後者則在模板中列印一個表示式的結果。

2. IDEs 整合
許多IDE支援Twig語法高亮和自動完成標籤:
※ TextMate 通過 Twig Bundle
※ Vim 通過 Jinja syntax 外掛vim-twig 外掛
※ NetBeans 通過 Twig syntax 外掛(7.2+)
※ PhpStorm(原生2.1+)
※ Eclipse 通過 Twig plugin
※ Sublime 通過 Twig bundle
※ GtkSourceView 通過 Twig language definition
※ Coda and SubEthaEdit 通過 Twig syntax mode
※ Coda 2 通過 other Twig syntax mode
※ Komodo and Komodo Edit 通過 Twig highlight/syntax check mode
※ Notepad++ 通過 Notepad++ Twig Highlighter
※ Emacs 通過 web-mode.el

3. 變數
應用程式將變數傳遞到操作的模板中。你也可以訪問變數的屬性或元素。一個變數的視覺化表示在很大程度上依賴於應用程式提供的值。你可以使用點(.)或所謂的下標語法([])來訪問變數的屬性(PHP物件的方法或屬性,PHP陣列的元素)。

1
2
{{ foo.bar }}
{{ foo['bar'] }}

當屬性中包含特殊字元(如 – 這會被解釋為減號操作符),使用attribute()函式來替代使用點(.)訪問變數屬性:

1
2
{# equivalent to the non-working foo.data-foo #}
{{ attribute(foo, 'data-foo') }}

重要提示:要知道,大括號不是變數的一部分,print語句除外。當訪問標籤內的變數,不要把大括號加在變數上。

如果一個變數或屬性不存在,strict_variables選項設定為false時,您將收到一個空值;另外,如果strict_variables設定為true,Twig將會丟擲一個錯誤(參照見environment options

變數呼叫機制
為了方便起見,在PHP表現層呼叫foo.bar時,會進行以下操作:

a.1 檢查foo是否是個陣列,並檢查bar是否是有效的元素
a.2 如果不是,foo是個物件,並檢查bar是否是有效的屬性
a.3 如果不是,foo是個物件,並檢查bar是否是有效方法。(即使bar是一個構造器。那麼請使用__construct()方法替代)
a.4 如果不是,foo是個物件,會檢查getBar()是否是有效的方法
a.5 如果不是,foo是個物件,會檢查isBar()是否是有效的方法
a.6 如果不是,返回空值(null)
a.7 檢查foo是一個陣列和bar是一個有效的元素;
a.8 如果沒有,則返回null值。

提示:如果你想訪問一個變數的動態屬性,使用attribute()函式來代替。

4. 全域性變數
下面的變數在模板中總是可用:
_self: 引用當前模版;
_context: 引用當前的上下文;
_charset: 引用當前的字符集。

5. 設定變數
您可以將值賦給內部程式碼塊中的變數。賦值使用set標籤:

1
2
3
{% set foo = 'foo' %}
{% set foo = [1, 2] %}
{% set foo = {'foo': 'bar'} %}

6. 過濾器
變數可以通過過濾器進行修改。過濾器和變數之間使用管道符號(也就是豎線 | )分隔開,過濾器括號中可能有可選的引數。多個過濾器可以串連使用,濾波器的輸出會被應用於下一個過濾器。

下面的示例是從名稱中刪除所有的HTML標籤並應用title-cases格式化:

1
{{ name|striptags|title }}

過濾器接受括號中的引數。 這個例子將用逗號連線一個列表:

1
{{ list|join(', ') }}

要對一段程式碼應用過濾器,只要使用filter標籤把它包起來:

1
2
3
{% filter upper %}
    This text becomes uppercase
{% endfilter %}

訪問過濾器頁面,以瞭解更多關於內建過濾器。

7. 函式
函式可以被呼叫來生成內容。函式是通過它們的[函式名+()]進行呼叫的,可能還帶有引數。
例如,range()函式返回一個包含一個整數等差數列的列表:

1
2
3
{% for i in range(0, 3) %}
    {{ i }},
{% endfor %}

訪問函式頁面,以瞭解更多關於內建函式。

8. 命名引數
1.12版本新特性:對命名引數的支援被新增到Twig 1.12版。

1
2
3
{% for i in range(low=1, high=10, step=2) %}
    {{ i }},
{% endfor %}

使用命名引數,讓你的模板更明確的瞭解,您作為引數傳遞的值的含義:

1
2
3
4
5
{{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
 
{# versus (對比) #}
 
{{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}

命名引數還允許您跳過一些你不希望更改預設值的引數:

1
2
3
4
5
{# the first argument is the date format, which defaults to the global date format if null is passed #}
{{ "now"|date(null, "Europe/Paris") }}
 
{# or skip the format value by using a named argument for the time zone #}
{{ "now"|date(timezone="Europe/Paris") }}

您也可以在一個呼叫中使用佔位引數和命名引數,在這種情況下,佔位引數必須在命名引數之前:

1
{{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }}

提示:每個函式和過濾器的文件頁面,都有一段內容,列出它們支援的所有引數名稱。

9. 控制結構
控制結構指的是所有這些控制程式流程的程式碼:條件語句(如:if/elseif/else)、for迴圈以及類似的程式碼塊。控制結構出現在{%…%}塊內。
例如,要顯示一個由變數(users)提供的使用者列表,使用for標籤:

1
2
3
4
5
6
<h1>Members</h1>
<ul>
    {% for user in users %}
        <li>{{ user.username|e }}</li>
    {% endfor %}
</ul>

if標籤可以用於測試表示式:

1
2
3
4
5
6
7
{% if users|length > 0 %}
    <ul>
        {% for user in users %}
            <li>{{ user.username|e }}</li>
        {% endfor %}
    </ul>
{% endif %}

訪問tags頁面,以瞭解更多關於內建標籤。

10. 註釋
要在模板中註釋掉一部分,使用註釋語法{#…#}。這對於除錯或新增資訊給其他模板設計者或自己看會很有用:

1
2
3
4
5
{# note: disabled template because we no longer use this
    {% for user in users %}
        ...
    {% endfor %}
#}

11. 包含其他模板
包含一個模板時,include標籤很有用,它會返回該模板(子模版)的內容呈現到當前模版(父模版):

1
{% include 'sidebar.html' %}

預設情況下每個被包含的模板都會傳遞當前上下文(context)。傳遞給父模板的上下文,還包括在子模板中定義的變數:

1
2
3
{% for box in boxes %}
    {% include "render_box.html" %}
{% endfor %}

被包含的模板 render_box.html 能夠訪問變數 box。

模板的檔名取決於模板載入器。例如,Twig_Loader_Filesystem允許你通過給檔名來訪問其他模板。您可以訪問以斜線分隔的子目錄中的模板:

1
{% include "sections/articles/sidebar.html" %}

此行為取決於應用程式中嵌入Twig。

12. 模板繼承

Twig最強大的部分是模板繼承。模板繼承允許你建立一個基本的”骨架”模板,包含您的網站的所有公用的元素,並定義一些區塊(block)讓子模板可以覆蓋。
聽起來似乎很複雜,但其實這是非常基本的。通過一個例子將容易理解它。
讓我們定義一個基本模板:base.html。它定義了一個簡單的HTML框架文件,假設是你要使用的一個簡單的兩列分佈的頁面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="style.css" />
            <title>{% block title %}{% endblock %} - My Webpage</title>
        {% endblock %}
    </head>
    <body>
        <div id="content">{% block content %}{% endblock %}</div>
        <div id="footer">
            {% block footer %}
                &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
            {% endblock %}
        </div>
    </body>
</html>

在這個例子中,block標籤定義了四個可讓子模板填充的區塊(block)。所有的blcok標籤的作用是告訴模板引擎:一個子模板可能會覆蓋模板的那些部分(也就是會覆蓋區塊)。

一個子模板看起來可能像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% extends "base.html" %}
 
{% block title %}Index{% endblock %}
{% block head %}
    {{ parent() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
        Welcome to my awesome homepage.
    </p>
{% endblock %}

擴充套件標籤(extends)是這裡的關鍵。它告訴模板引擎,這個模板擴充套件於另一個模板。當模板系統評估此模板時,它首先會找到當前模版的父模版。擴充套件標籤(extends)必須是在模板中的第一個標籤。

請注意,由於子模板沒有定義 footer 區塊,所以將會使用父模板中的值來代替。

是有可能通過使用 parent函式來呈現父區塊的內容。這使得你可以返回父區塊的結果:

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

提示1:在擴充套件標籤(extends)文件頁面介紹了更高階的功能,如塊巢狀,適用範圍,動態繼承和有條件的繼承。
提示2:在use標籤的幫助下,通過所謂的橫向重用Twig還支援多重繼承。這是常規模板很少需要使用到的高階功能。

13. HTML轉義

當從模版生成的HTML時,總有一個風險,即一個變數將包含某些影響最終HTML的字元。有兩種方法解決此問題:手動轉義每個變數或預設地自動轉義一切。

兩種方法Twig都支援,並且自動轉義是預設啟用的。
提示:escaper擴充套件是啟用狀態的時候(預設是這樣),自動轉義才有效。

13.1 使用手動轉義工作

如果手動轉義被啟用,轉義變數就是你的責任了,如果你需要的話。需要轉義什麼呢?任何你不信任的變數。
轉義功能通過 escape 或 e 過濾器來轉義變數:

1
{{ user.username|e }}

轉義過濾器預設使用的HTML策略,但根據轉義的上下文,你可能會想要明確地使用任何其他可用的策略:

1
2
3
4
{{ user.username|e('js') }}
{{ user.username|e('css') }}
{{ user.username|e('url') }}
{{ user.username|e('html_attr') }}

13.2 使用自動轉義工作

無論自動轉義啟用與否,你都可以使用autoescape標籤來標記模板的一部分進行轉義或不轉義:

1
2
3
{% autoescape %}
    Everything will be automatically escaped in this block (using the HTML strategy)
{% endautoescape %}

預設情況下,自動轉義使用HTML轉義的策略。如果您在其他情況下輸出變數,你需要明確地使用適當的轉義策略來轉義他們:

1
2
3
{% autoescape 'js' %}
    Everything will be automatically escaped in this block (using the JS strategy)
{% endautoescape %}

13.3 轉義

有時希望或必需讓Twig忽略將其他處理作為變數或區塊(block)。例如,如果使用預設的語法,想要使用 {{ 作為原始模板中的字串,而並不是作為使用變數的分隔符,你必須使用一個技巧。
最簡單的方法是通過使用一個變數表示式來輸出變數的分隔符({{):

1
{{ '{{' }}

對於更大的部分,使用verbatim標籤進行標記才是有意義的。

14. 巨集(Macros)

提示:版本1.12新特性:在Twig 1.12 中新增了對預設引數值的支援。
巨集是可以和常規的程式語言相媲美的功能。它們對於常用的HTML片段的重用非常有用,而不需要不斷重複自己。巨集通過macro 標籤定義。下面是由巨集來渲染一個表單元素的例子(稱為forms.html):

1
2
3
{% macro input(name, value, type, size) %}
    <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}

巨集可以在任何模板中定義,並且在使用之前,需要通過 import 標籤來匯入:

1
2
3
{% import "forms.html" as forms %}
 
<p>{{ forms.input('username') }}</p>

或者,您也可以通過from標籤從一個模版中匯入單獨的巨集名稱到當前模版,並且可選地使用別名來命名它們:

1
2
3
4
5
6
7
8
{% from 'forms.html' import input as input_field %}
 
<dl>
    <dt>Username</dt>
    <dd>{{ input_field('username') }}</dd>
    <dt>Password</dt>
    <dd>{{ input_field('password', '', 'password') }}</dd>
</dl>

巨集呼叫時,如果沒有提供巨集引數的話,預設值將會被定義:

1
2
3
{% macro input(name, value = "", type = "text", size = 20) %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
{% endmacro %}

15. 表示式

Twig允許在任何地方使用表示式。這和常規的PHP非常類似,甚至如果你並不使用PHP的話,你會感覺很舒服。
提示:運算子優先順序如下,首先列出的是最低優先順序的操作:

b-and, b-xor, b-or, or, and, ==, !=, <, >, >=,
<=, in, matches, starts with, ends with, .., +,
-, ~, *, /, //, %, is, **, |, [], and

1
2
3
4
5
6
7
{% set greeting = 'Hello ' %}
{% set name = 'Fabien' %}
 
{{ greeting ~ name|lower }}   {# Hello fabien #}
 
{# use parenthesis to change precedence #}
{{ (greeting ~ name)|lower }} {# hello fabien #}

15.1 文字

提示:版本1.5新特性:Twig 1.5中對雜湊鍵作為名稱和表示式新增了支援。

表示式的最簡單形式是文字。文字在PHP型別中表示,如字串,數字和陣列。存在下面這些文字:

※ “Hello World”:兩個雙引號或單引號之間的任何內容都是一個字串。當你在模版中需要一個字串的時候(例如:函式呼叫的引數、過濾器或者僅僅只是擴充套件或包含一個模版),它們非常有用。一個字串可以包含一個分隔符,如果它前面有一個反斜槓(\)的話,例如:’It\’s good’。
※ 42 / 42.23:整數和浮點數是由剛寫下的數字建立的。如果一個數存在一個點,那它就是一個浮點數,否則是個整數。
※ ["foo", "bar"]: 陣列被定義為由逗號(,)分隔開、被方括號([])包裹著的表示式序列。
※ {“foo”: “bar”}:雜湊表被定義為一個由逗號(,)分隔開、被花括號({})包裹著的、由[鍵]和[值]組成的列表。

1
2
3
4
5
6
7
8
9
10
11
{# keys作為字串 #}
{ 'foo': 'foo', 'bar': 'bar' }
 
{# keys 作為名稱(相當於以前的雜湊表) -- as of Twig 1.5 #}
{ foo: 'foo', bar: 'bar' }
 
{# keys 作為整數 #}
{ 2: 'foo', 4: 'bar' }
 
{# keys 作為表示式 (表示式必須用括號包裹起來) -- as of Twig 1.5 #}
{ (1 + 1): 'foo', (a ~ 'b'): 'bar' }

※ true / false: true 代表值為真,false 代表值為假。
※ null:null表示沒有特定的值。這是當一個變數不存在時返回的值。none 是 null 的一個別名。

陣列和雜湊可以巢狀:

1
{% set foo = [1, {"foo": "bar"}] %}

提示:使用雙引號或單引號字串對效能沒有影響,但只支援在雙引號字串的插入變數值。

15.2 計算
Twig允許你對值進行計算。在模板中雖然很少有用,但因為完整性的緣故而存在。下面是被支援的操作符:

※ + :將兩個物件加在一起(運算元被強制轉換為數字)。 {{1+1}}是2。
※ - :從第一個數減去第二個數字。 {{3 – 2}}為1。
※ / :兩個數相除。返回的值將是一個浮點數。 {{1/2}}是{{0.5}}。
※  :計算一個整數被除的餘數。 {{11%7}}是4。
※ // :兩個數相除並返回的向下取整的整數結果。 {{20//7}}為2,{{-20//7}}是-3(這只是round過濾器的語法修飾)。
※ * :左運算元與右運算元相乘。 {{2*2}}將返回4。
※ ** :左運算元(n)的右運算元(m)次冪。(也就是n的m次方,n^m) {{2 ** 3}}將返回8。

15.3 邏輯

您可以將多個表示式使用下列運算子:

※ and: 如果左邊和右邊的運算元都為真,則返回true。
※ or: 如果左邊或右邊的運算元為真,則返回true。
※ not: 否定一個宣告。
※ (expr): 構成一組表示式。

提示:Twig還支援位運算子(b-and, b-xor, and b-or)。

15.4 比較
以下比較操作符在任何表示式中都支援: ==, !=, <, >, >=, <=。
您也可以檢查一個字串是否以另一個字串開頭或結尾:

1
2
3
4
5
{% if 'Fabien' starts with 'F' %}
{% endif %}
 
{% if 'Fabien' ends with 'n' %}
{% endif %}

對於複雜的字串比較時,matches操作符允許你使用正規表示式:

1
2
{% if phone matches '{^[\d\.]+$}' %}
{% endif %}

15.5 包含操作符

in 操作符進行包含測試。 如果左運算元是包含在左運算元,則返回true:

1
2
3
4
5
{# returns true #}
 
{{ 1 in [1, 2, 3] }}
 
{{ 'cd' in 'abcde' }}

提示:您可以使用此過濾器來對字串、陣列或實現Traversable介面的物件進行包含測試。

要執行一個反面測試,使用 not in 操作符:

1
2
3
{% if 1 not in [1, 2, 3] %}
{# 以上等同於以下 #}
{% if not (1 in [1, 2, 3]) %}

15.6 測試操作符

is 操作符可以進行測試。測試可以用於測試針對一種常見的表示式的變數。右運算元是測試的名稱:

1
2
{# 找出是奇數的變數 #}
{{ name is odd }}

測試也可以接受引數:

1
{% if post.status is constant('Post::PUBLISHED') %}

通過使用 is not 操作符,測試可以被否定:

1
2
3
{% if post.status is not constant('Post::PUBLISHED') %}
{# 以上等同於以下 #}
{% if not (post.status is constant('Post::PUBLISHED')) %}

訪問tests頁面,以瞭解更多關於內建的測試。

15.7 其它操作符

提示:1.12.0版本新特性:Twig 1.12.0 版本對擴充套件的三元運算子中新增了支援。
下列運算子是非常有用的,但不屬於任何其他類別:
※ .. :建立一個基於前運算元和後運算元的序列(這只是range函式的語法修飾)。
※ | :應用一個過濾器。
※ ~ :所有的運算元轉換為字串並將其連線起來。{{ “Hello ” ~ name ~ “!” }} 將返回 (假設名字是’John’) Hello John!.
※ . , [] :獲取一個物件的屬性。
※ ?: :三元運算子(?:)。

1
2
3
4
5
{{ foo ? 'yes' : 'no' }}
 
{# as of Twig 1.12.0 #}
{{ foo ?: 'no' }} is the same as {{ foo ? foo : 'no' }}
{{ foo ? 'yes' }} is the same as {{ foo ? 'yes' : '' }}

15.8 字串插值

提示:1.5版本新特性: 字串插值被新增到了 Twig 1.5版本中。
字串插值(#{表示式})允許任何有效的表示式出現在雙引號包裹字串中。執行的結果中該表示式會被插入字串:

1
2
{{ "foo #{bar} baz" }}
{{ "foo #{1 + 2} baz" }}

16. 空白符控制

提示:1.1版本新特性: 標記級別的空白符控制被新增到了 Twig 1.1版本中。
模板標籤後的第一個換行符會被自動移除(就像在PHP中)。其它的空白符就不再被模板引擎修改,所以每個空白符(空格,製表符,換行符等)將會原封不動地被返回(給view)。

使用 spaceless 標籤可以把HTML標籤之間的空白符去掉:

1
2
3
4
5
6
7
{% spaceless %}
    <div>
        <strong>foo bar</strong>
    </div>
{% endspaceless %}
 
{# 輸出將會是:<div><strong>foo bar</strong></div> #}

另外,對於 spaceless 標籤,你也可以在每個標籤級別上控制空白符。通過在你的標籤上使用空白符控制修飾,你可以去掉領先或尾隨空白符:

1
2
3
4
5
6
7
{% set value = 'no spaces' %}
{#- 沒有領先或尾隨的空白符 -#}
{%- if true -%}
    {{- value -}}
{%- endif -%}
 
{# 輸出:'no spaces' #}

在上面的示例中顯示了預設的空白符控制修飾符,以及如何使用它來除去標籤周圍的空白符。不過預設會去掉標籤兩邊的所有的空白符。實際上,你也可以使用它只去掉標籤一側的空白符:

1
2
3
4
{% set value = 'no spaces' %}
<li>    {{- value }}    </li>
 
{# 輸出:'<li>no spaces    </li>' #}

17. 擴充套件

Twig可以很容易被擴充套件。如果你正在尋找新的標籤,過濾器,或函式,你看看Twig官方擴充套件庫
如果你想建立自己的擴充套件,請閱讀建立一個擴充套件的篇章。


相關文章