何必再说twig调⽤php函数,为模版设计师⽽⽣的Twig(下)-Twig使⽤长征的感人故事
指南
《为模版设计师⽽⽣的Twig》的原⽂篇幅较长,因此分成两部分进⾏翻译。和第⼀部分《为模版设计师⽽⽣的Twig(上)》⼀样,本⽂还是介绍模板引擎的语法和语义,主要介绍上⼀⽚中余下的部分,包括:模板继承、HTML转义、宏(Macros)、表达式、空⽩符控制、扩展等内容。
12. 模板继承
Twig最强⼤的部分是模板继承。模板继承允许你建⽴⼀个基本的"⾻架"模板,包含您的⽹站的所有公⽤的元素,并定义⼀些区块(block)让⼦模板可以覆盖。
听起来似乎很复杂,但其实这是⾮常基本的。通过⼀个例⼦将容易理解它。
让我们定义⼀个基本模板:ba.html。它定义了⼀个简单的HTML框架⽂档,假设是你要使⽤的⼀个简单的两列分布的页⾯:
html>
{% block head %}
{% block title %}{% endblock %} - My Webpage
{% endblock %}
{% block content %}{% endblock %}
{% block footer %}
© Copyright 2011 by you.
{% endblock %}
在这个例⼦中,block 标签定义了四个可让⼦模板填充的区块(block)。所有的blcok标签的作⽤是告诉模板引擎:⼀个⼦模板可能会覆盖模板的那些部分(也就是会覆盖区块)。
⼀个⼦模板看起来可能像这样:
{% extends "ba.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ parent() }}
.important { color: #336699; }
{% endblock %}
{% block content %}
名歌经典Index
Welcome to my awesome homepage.
{% endblock %}
扩展标签( extends )是这⾥的关键。它告诉模板引擎,这个模板扩展于另⼀个模板。当模板系统评估此模板时,它⾸先会找到当前模版的⽗模版。扩展标签(extends)必须是在模板中的第⼀个标签。
请注意,由于⼦模板没有定义 footer 区块,所以将会使⽤⽗模板中的值来代替。
通过使⽤ parent 函数来呈现⽗区块的内容。这使得你可以返回⽗区块的结果:
{% block sidebar %}
信不信由你博物馆Table Of Contents
...
{{ parent() }}
{% endblock %}
提⽰1:在扩展标签(extends)⽂档页⾯介绍了更⾼级的功能,如块嵌套,适⽤范围,动态继承和有条件的继承。
提⽰2:在u标签的帮助下,通过所谓的横向重⽤Twig还⽀持多重继承。这是常规模板很少需要使⽤到的⾼级功能。
13. HTML转义
当从模版⽣成的HTML时,总有⼀个风险,即⼀个变量将包含某些影响最终HTML的字符。有两种⽅法解决此问题:⼿动转义每个变量或默认地⾃动转义⼀切。两种⽅法Twig都⽀持,并且⾃动转义是默认启⽤的。
提⽰:escaper扩展是启⽤状态的时候(默认是这样),⾃动转义才有效。
13.1 使⽤⼿动转义⼯作
如果⼿动转义被启⽤,转义变量就是你的责任了,如果你需要的话。需要转义什么呢?任何你不信任的变量。
转义功能通过 escape 或 e 过滤器来转义变量:
{{ ur.urname|e }}
转义过滤器默认使⽤的HTML策略,但根据转义的上下⽂,你可能会想要明确地使⽤任何其他可⽤的策略:
{{ ur.urname|e('js') }}
{{ ur.urname|e('css') }}
{{ ur.urname|e('url') }}
{{ ur.urname|e('html_attr') }}
13.2 使⽤⾃动转义⼯作
⽆论⾃动转义启⽤与否,你都可以使⽤ autoescape 标签来标记模板的⼀部分进⾏转义或不转义:
{% autoescape %}
Everything will be automatically escaped in this block (using the HTML strategy)
{% endautoescape %}
默认情况下,⾃动转义使⽤HTML转义的策略。如果您在其他情况下输出变量,你需要明确地使⽤适当的转义策略来转义他们:
{% autoescape 'js' %}
Everything will be automatically escaped in this block (using the JS strategy)
{% endautoescape %}
13.3 转义
有时希望或必需让Twig忽略将其他处理作为变量或区块(block)。例如,如果使⽤默认的语法,想要使⽤ {{ 作为原始模板中的字符串,⽽并不是作为使⽤变量的分隔符,你必须使⽤⼀个技巧。
最简单的⽅法是通过使⽤⼀个变量表达式来输出变量的分隔符({{):
{{ '{{' }}
对于更⼤的部分,使⽤verbatim标签进⾏标记才是有意义的。
14. 宏(Macros)
提⽰:版本1.12新特性:在Twig 1.12 中添加了对默认参数值的⽀持。
宏是可以和常规的编程语⾔相媲美的功能。它们对于常⽤的HTML⽚段的重⽤⾮常有⽤,⽽不需要不断重复⾃⼰。宏通过 macro 标签定义。下⾯是由宏来渲染⼀个表单元素的例⼦(称为forms.html):
{% macro input(name, value, type, size) %}
{% endmacro %}
宏可以在任何模板中定义,并且在使⽤之前,需要通过 import 标签来导⼊:
{% import "forms.html" as forms %}
{{ forms.input('urname') }}
或者,您也可以通过 from 标签从⼀个模版中导⼊单独的宏名称到当前模版,并且可选地使⽤别名来命名它们:
{% from 'forms.html' import input as input_field %}
Urname
{{ input_field('urname') }}
Password
{{ input_field('password', '', 'password') }}
宏调⽤时,如果没有提供宏参数的话,默认值将会被定义:
{% macro input(name, value = "", type = "text", size = 20) %}
{% endmacro %}
15. 表达式
Twig允许在任何地⽅使⽤表达式。这和常规的PHP⾮常类似,甚⾄如果你并不使⽤PHP的话,你会感觉很舒服。
提⽰:运算符优先级如下,⾸先列出的是最低优先级的操作:
b-and, b-xor, b-or, or, and, ==, !=, , >=, <=, in, matches,
starts with, ends with, .., +, -, ~, *, /, //, %, is, **, |, [], and
{% t greeting = 'Hello ' %}
牛排骨怎么做
{% t name = 'Fabien' %}
{{ greeting ~ name|lower }} {# Hello fabien #}
{# u 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"}:哈希表被定义为⼀个由逗号(,)分隔开、被花括号({})包裹着的、由[键]和[值]组成的列表。
{# 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 / fal: true 代表值为真,fal 代表值为假。
null:null表⽰没有特定的值。这是当⼀个变量不存在时返回的值。none 是 null 的⼀个别名。
数组和哈希可以嵌套:
{% t 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 ⽐较
以下⽐较操作符在任何表达式中都⽀持: ==, !=, , >=, <=。
您也可以检查⼀个字符串是否以另⼀个字符串开头或结尾:
{% if 'Fabien' starts with 'F' %}
{% endif %}
{% if 'Fabien' ends with 'n' %}
{% endif %}
对于复杂的字符串⽐较时,matches操作符允许你使⽤正则表达式:
{% if phone matches '{^[\d\.]+$}' %}
{% endif %}
戚继光墓15.5 包含操作符
in 操作符进⾏包含测试。 如果左操作数是包含在左操作数,则返回true:
{# returns true #}
{{ 1 in [1, 2, 3] }}
{{ 'cd' in 'abcde' }}
提⽰:您可以使⽤此过滤器来对字符串、数组或实现Traversable接⼝的对象进⾏包含测试。
要执⾏⼀个反⾯测试,使⽤ not in 操作符:
{% if 1 not in [1, 2, 3] %}
{# 以上等同于以下 #}
{% if not (1 in [1, 2, 3]) %}
15.6 测试操作符
is 操作符可以进⾏测试。测试可以⽤于测试针对⼀种常见的表达式的变量。右操作数是测试的名称:
{# 找出是奇数的变量 #}
{{ name is odd }}
测试也可以接受参数:
{% if post.status is constant('Post::PUBLISHED') %}
通过使⽤ is not 操作符,测试可以被否定:
{% 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!. ., [ ] : 获取⼀个对象的属性。
: : 三元运算符(:)。