一、 Twig小技巧
{{ aa ?? '111' }} == {{ aa|default('111') }}
{% set aa = '111' %}
{{ "aa的值是" ~ aa ~ "的数" }} == {{ "aa的值是#{aa}的数" }}
{% set a = {3: 'aaa', 4: 'bbb'} %}
{% set b = {5: 'ccc', 6: 'ddd'} %}
{{ a|merge(b) }} // {0: 'aaa', 1: 'bbb', 2: 'ccc', 3: 'ddd'}
{{ a + b }} // {3: 'aaa', 4: 'bbb', 5: 'ccc', 6: 'ddd'}
{% block title %}
{{ page_title|title }}
{% endblock %}
==
{% block title page_title|title %}
二、 Twig入门
1、注释
{# ... #} 包围的内容会被注释掉,可以是单行 也可以是多行。
2、变量
程序会传递给模板若干变量,你需要在模板里输出他们。例如输出 $hello
{{ hello }}
如果传递给模板的是对象或者数组,你可以使用点 . 来输出对象的属性或者方法,或者数组的成员。或者你可以使用下标的方式
{{ foo.bar }}
{{ foo['bar'] }}
3、全局变量
Twig定义了一些全局变量,当然,你也可以向其添加你自己的全局模板变量。
图1
4、变量赋值(set 标签)
{% set foo = 'foo' %}
{% set foo = [1, 2] %}
{% set foo = {'foo': 'bar'} %}
{% set foo = [1, {"foo": "bar"}] %}
5、过滤器 Firters
目前内置的过滤器包括 date、format、replace、number_format、url_encode、json_encode、convert_encoding、title、capitalize、nl2br、upper、lower、striptags、 join、reverse、length、sort 、default、keys、escape、raw、merge
变量可以被过滤器修饰。过滤器和变量用(|)分割开。过滤器也是可以有参数的。过滤器也可以被多重使用
//striptags表示去除html标签,title表示每个单词的首字母大写
{{ name|striptags|title }}
5-1、date过滤器,这个过滤器和php的date函数无限类似
{{ createtime|date("m/d/Y") }}
{{ "now"|date("m/d/Y") }} {# 当前时间 #}
{{ createtime|date("U") }} {# 输出时间戳 #}
如果想在格式里输出字母,需要在每个字母前输入,不能输入中文字符
{{ createtime|date("F jS \\a\\t g:ia") }}
可以指定时区
{{ createtime|date("m/d/Y", "Europe/Paris") }}
5-2、format过滤器,和php的printf函数一样,用来替换占位符
{{ "I like %s and %s."|format(foo, "bar") }}
//输出 'I like foo and bar'.
5-3、replace过滤器
{{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }}
//输出 'I like foo and bar'
5-4、number_format过滤器
它是php函数 number_format 的一个包装
{{ 200.35|number_format }}
5-5、url_encode过滤器
这个直接使用PHP的urlencode
函数
{{ data|url_encode() }}
5-6、json_encode过滤器
直接使用json_encode
函数
{{ data|json_encode() }}
5-7、convert_encoding过滤器
转换一个字符串,第一个参数是输出编码,第二个参数是输入编码,本函数依赖于iconv 或者mbstring 所以至少需要安装一个
{{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
5-8、title过滤器
会让每个单词的首字母大写。
{{ 'my first car'|title }}
//输出:'My First Car'
5-9、capitalize过滤器
会把字符串变成 首字母大写,其余字母小写的格式
{{ 'my first car'|capitalize }}
//输出:'My first car'
5-10、upper 过滤器
让字符串变大写
{{ title|upper }}
5-11、lower 过滤器
让字符串变小写
{{ title|lower }}
5-12、striptags过滤器
直接使用的是strip_tags函数,去除html标签
{{ name|striptags }}
5-13、nl2br过滤器
会把换行符\n 变成
{{ "I like Twig.\nYou will like it too."|nl2br }}
//输出:'I like Twig.<br />You will like it too.'
5-14、join过滤器
用来将一个数组的内容连接起来,并用指定的字符串分割
{{ [1, 2, 3]|join }}
//输出:123
{{ [1, 2, 3]|join('|') }}
//输出 1|2|3
5-15、reverse 过滤器
反转一个数组,或者是一个实现了Iterator接口的对象
{% for use in users|reverse %}
...
{% endfor %}
5-16、length过滤器
返回一个数组或者字符串的长度
{% if users|length > 10 %}
...
{% endif %}
5-17、sort过滤器
使用的是sort函数
{% for use in users|sort %}
...
{% endfor %}
5-18、default过滤器
当变量没定义或者为空的时候,返回预先设置的内容
{{ var|default('var is not defined') }}
{{ var.foo|default('foo item on var is not defined') }}
{{ var['foo']|default('foo item on var is not defined') }}
{{ ''|default('passed var is empty') }}
5-19、keys过滤器
返回key数组
{% for key in array|keys %}
...
{% endfor %}
5-20、escape过滤器
主要转义 & < > ' " 。并且它有个简写方式 e。他使用的是php函数 htmlspecialchars
{{ user.username|escape }}
{{ user.username|e }}
//还可以转义 js
{{ user.username|escape('js') }}
{{ user.username|e('js') }}
5-21、raw过滤器
用于在autoescape标签内部,标记出不需要转义的内容。
{% autoescape true %}
{{ var|raw }}
{% endautoescape %}
5-22、merge过滤器
用来合并数组
{% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
{% set items = items|merge({ 'peugeot': 'car' }) %}
{# 合成后的数组为 { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
过滤器也可以用在代码块中
{% filter upper %}
This text becomes uppercase
{% endfilter %}
Twig默认情况下有一大群的标签(tags)和过滤器(filters)可以使用。当然你也可以根据需要添加扩展。注册一个Twig扩展非常容易, 创建一个新服务并把它标记为Twig.extension 标签。就跟你看到的一样,Twig也支持功能和新功能的添加。比如,下面使用一个标准 的for标签和cycle功能函数来打印10个div 标签,用odd、even 类代替
{% for i in 0..10 %}
<div alss="{{ cycle(['odd','even'],i) }}">
<!--一些其它HTML -->
</div>
{% emdfor %}
{% set start_year = date() | date('Y') %}
{% set end_year = start_year + 5 %}
{% for year in start_year..end_year %}
<p>{{ start_year }} -- {{ end_year }} --{{ cycle(['odd', 'even'], loop.index0) }}</p>
{% endfor %}
//输出:
//<p>2020 -- 2025 --odd</p>
//<p>2020 -- 2025 --even</p>
//<p>2020 -- 2025 --odd</p>
//<p>2020 -- 2025 --even</p>
//<p>2020 -- 2025 --odd</p>
//<p>2020 -- 2025 --even</p>
{% set fruits = ['apple', 'orange', 'citrus'] %}
{% for i in 0..10 %}
<p>{{ cycle(fruits, i) }}</p>
{% endfor %}
//输出:
//<p>apple</p>
//<p>orange</p>
//<p>citrus</p>
//<p>apple</p>
//<p>orange</p>
//<p>citrus</p>
//<p>apple</p>
//<p>orange</p>
//<p>citrus</p>
//<p>apple</p>
//<p>orange</p>
5-23、round过滤器
数字截取
{{ 40.255|round(2) }} -> 40.26
{{ 40.253|round(2) }} -> 40.25
round(num, level)
图2
6、函数 Function
目前twig内建的函数包括 attribute, block, constant, cycle, dump, parent, random, range.
attribute函数,他就相当于是个. 操作符
{{ attribute(object, method) }}
{{ attribute(object, method, arguments) }}
{{ attribute(array, item) }}
block函数,输出block区块的内容。
<title>{% block title %}{% endblock %}</title>
<h1>{{ block('title') }}</h1>
{% block body %}{% endblock %}
constant函数,读取常量
{{ some_date|date(constant('DATE_W3C')) }}
{{ constant('Namespace\\Classname::CONSTANT_NAME') }}
cycle函数,循环输出数组的内容
{% set fruits = ['apple', 'orange', 'citrus'] %}
{% for i in 0..10 %}
{{ cycle(fruits, i) }}
{% endfor %}
dump函数,打印变量,就是用的php的var_dump函数,需要开启debug模式
$twig = new Twig_Environment($loader, $config);
$twig->addExtension(new Twig_Extension_Debug());
你可以传递一个或者多个变量,如果你不传递变量,他会打印所有变量
{{ dump(user, categories) }}
{{ dump() }}
parent函数,获取父block的内容,在你准备增加而不是覆盖的时候特别有用
{% extends "base.html" %}
{% block sidebar %}
<h3>Table Of Contents</h3>
{{ parent() }}
...
{% endblock %}
random函数,从一个数组中随机返回一个
{{ random(['apple', 'orange', 'citrus']) }}
range函数,返回一个数字数组,从第一个参数开始,到第二个参数结束(包含第二个),第三个参数是步长(可以省略)。 和0..10一样
{% for i in range(0, 3) %}
{{ i }},
{% endfor %}
{# returns 0, 1, 2, 3 #}
7、tags
目前支持的tags包括
`for if macro filter set extends block include import from use spaceless autoescape raw flush do`
7-1、for标签(基于数组的循环)
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
基于数字的循环,特别要注意,这里会输出0-10 也就是11个数字。
{% for i in 0..10 %}
{{ i }}
{% endfor %}
基于字母的循环
{% for letter in 'a'..'z' %}
{{ letter }}
{% endfor %}
在循环体内部的变量
loop.length
,loop.revindex
, loop.revindex0
,loop.last
这几个值只有在被循环的是php数组 或实现了Countable 接口的类,才有效。twig在循环内部不支持
break
和continue
语句,你只能通过过滤器去跳过一些循环
<ul>
{% for user in users if user.active %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
else 分支 如果 users是个空数组就会输出no user found 。
<ul>
{% for user in users %}
<li>{{ user.username}}</li>
{% else %}
<li><em>no user found</em></li>
{% endfor %}
</ul>
按keys循环
<h1>Members</h1>
<ul>
{% for key in users|keys %}
<li>{{ key }}</li>
{% endfor %}
</ul>
按keys,values循环
<h1>Members</h1>
<ul>
{% for key, user in users %}
<li>{{ key }}: {{ user.username|e }}</li>
{% endfor %}
</ul>
7-2、if标签
{% if users|length %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
{% if kenny.sick %}
Kenny is sick.
{% elseif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}
7-3、macro标签
macro(宏标签)类似于其他语言中的函数,常用于填充html标签,以下是一个例子,用来渲染<input>
{% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}
macro与函数的不同之处在于:
- 参数的默认值是通过macro块内部的 default过滤器来定义的。
- 参数总是可选的。
- 另外,就跟php函数一样,
macro
内部是无法使用外部的变量的。但你可以传递一个特殊变量_context
作为参数来获取整个内容。macro
可以被定义在任何的模板内,但在你使用之前需要使用imported
{% import "forms.html" as forms %}
<p>{{ forms.input('username') }}</p>
<p>{{ forms.input('password', null, 'password') }}</p>
如果你要在定义macro
的模板里使用,就不需要imported
可以使用特殊变量_self
<p>{{ _self.input('username') }}</p>
如果你要定义一个macro里 包含另一个macro,并且两个macro在同一个文件里,可以使用特殊变量_self
{% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}
{% macro wrapped_input(name, value, type, size) %}
<div class="field">
{{ _self.input(name, value, type, size) }}
</div>
{% endmacro %}
如果两个macro在不同的文件里,你需要使用import
{# forms.html #}
{% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}
{# shortcuts.html #}
{% macro wrapped_input(name, value, type, size) %}
{% import "forms.html" as forms %}
<div class="field">
{{ forms.input(name, value, type, size) }}
</div>
{% endmacro %}
7-4、filter标签
就是给整个区块使用过滤器
{% filter upper %}
This text becomes uppercase
{% endfilter %}
{% filter lower|escape %}
<strong>SOME TEXT</strong>
{% endfilter %}
7-5、extends标签
这个标签用来表示本模板继承自另外一个模板。和php一样,twig
不支持多重继承,所以你只能有一个extends
标签,而且要在模板的最上方。 我们先来定义一个“基模板” base.html
他就像一个骨架一个。
{# base.html.twig #}
<!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 %}
© Copyright 2011 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</div>
</body>
</html>
{% block %}标签定义了4个区块(block head, block title, block content, block footer),可以让子模板来填充内容。 block的作用就是告诉模板引擎,这里面的内容可以被子模板覆盖。
一个子模板大概类似于这样的
{% extends "base.html.twig" %}
{% 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 on my awesome homepage.
</p>
{% endblock %}
- extends是非常关键的,它告诉模板引擎,本模板继承自另一个模板(base.html.twig)。当模板引擎解析到本模板时,会首先载入父模板,
- extends标签应该是模板内的第一个标签。
- 如果子模板没有定义block footer ,那么父模板会用默认值代替。
注意:block标签的名字是不能重复的。如果你想让同一个block多次打印。可以使用block函数
<title>{% block title %}{% endblock %}</title>
<h1>{{ block('title') }}</h1>
{% block body %}{% endblock %}
父block 也许你会需要 父block的内容。可以使用parent函数,这很有用比如你想往一个block里添加内容而不是覆盖时。
{% block sidebar %}
<h3>Table Of Contents</h3>
{{ parent() }}
{% endblock %}
命名endblock 模板引擎 允许你命名结束标记,这样可读性会提高很多。
{% block sidebar %}
{% block inner_sidebar %}
...
{% endblock inner_sidebar %}
{% endblock sidebar %}
嵌套block 允许你嵌套生成block ,来形成更复杂的block
{% for item in seq %}
<li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}
简写block 以下这两种写法是等效的
{% block title %}
{{ page_title|title }}
{% endblock %}
{% block title page_title|title %}
动态继承 你可以用一个变量来继承不同的模板。
{% extends some_var %}
如果变量是一个twig模板对象,也可以。
$layout = $twig->loadTemplate('some_layout_template.html.twig');
$twig->display('template.twig', array('layout' => $layout));
1-2版本更新 你可以传递一个数组,twig会选择第一个存在的模板,来继承。
{% extends ['layout.html', 'base_layout.html.twig'] %}
条件继承
{% extends standalone ? "minimum.html.twig" : "base.html.twig" %}
7-6、include标签
载入一个模板,返回渲染的内容。载入的模板可以使用当前模板的变量
{% include 'header.html.twig' %}
Body
{% include 'footer.html.twig' %}
你可以给模板添加变量
{% include 'foo' with {'foo': 'bar'} %}
{% set vars = {'foo': 'bar'} %}
{% include 'foo' with vars %}
你也可以使用 only 关键字 来禁止载入的模板使用当前模板的变量,只能使用include 时with的变量
{% include 'foo' with {'foo': 'bar'} only %}
{% include 'foo' only %}
载入的模板名也可以是一个twig表达式
{% include some_var %}
{% include ajax ? 'ajax.html.twig' : 'not_ajax.html.twig' %}
也可以用twig模板对象
$template = $twig->loadTemplate('some_template.twig');
$twig->loadTemplate('template.twig')->display(array('template' => $template));
在模板加上 ignore missing 关键字,这样当模板不存在的时候就不会引发错误。
{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with {'foo': 'bar} %}
{% include "sidebar.html" ignore missing only %}
可以给include传递一个数组,他会自动载入第一个存在的模板
{% include ['page_detailed.html.twig', 'page.html.twig'] %}
7-7、import 标签
twig允许把一些常用的代码放入到macros(宏)里,这些macros被不同的模板导入。 有两种方法导入模板,你可以导入整个模板到一个变量里,或者只导入需要的几个macros 假如我们有个助手模块,来帮助我们渲染表单(forms.html.twig)
{% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}
{% macro textarea(name, value, rows) %}
<textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
{% endmacro %}
最简单,最灵活的办法就是导入整个模板。(把模板导入到 forms变量里)
{% import 'forms.html.twig' as forms %}
<dl>
<dt>Username</dt>
<dd>{{ forms.input('username') }}</dd>
<dt>Password</dt>
<dd>{{ forms.input('password', null, 'password') }}</dd>
</dl>
<p>{{ forms.textarea('comment') }}</p>
或者你可以导入模板的名字到当前的名字空间下。 (导入input,textarea 并把input重名为input_field)
{% from 'forms.html.twig' import input as input_field, textarea %}
<dl>
<dt>Username</dt>
<dd>{{ input_field('username') }}</dd>
<dt>Password</dt>
<dd>{{ input_field('password', '', 'password') }}</dd>
</dl>
<p>{{ textarea('comment') }}</p>
如果是当前模板内定义的macros,那就不必导入了,直接使用特殊变量_self
{# index.html.twig template #}
{% macro textarea(name, value, rows) %}
<textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
{% endmacro %}
<p>{{ _self.textarea('comment') }}</p>
那么你仍然可以导入_self到一个变量里。
{# index.html.twig template #}
{% macro textarea(name, value, rows) %}
<textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
{% endmacro %}
{% import _self as forms %}
<p>{{ forms.textarea('comment') }}</p>
7-8、from标签
参见 import标签
7-9、use标签
这个use标签主要是来解决模板只能从一个父模板继承,而你又想重用其他模板的问题,但是use标签只会导入block区块。 注意import只会导入宏macros,include会导入一切。这三个标签要区分清楚
{% extends "base.html.twig" %}
{% use "blocks.html.twig" %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}
而blocks.html.twig的内容是
{% block sidebar %}{% endblock %}
我们从blocks..html.twig导入了 block sidebar 运行的结果几乎等于
{% extends "base.html.twig" %}
{% block sidebar %}{% endblock %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}
要注意,被use标签导入的模板(上例中的block.html.twig),不能再继承别的模板,不能定义宏macros。但它可以再use其他模板。 另外use标签后面的文件名,不能是一个表达式。
当被导入了的block和主模板的block重名了,模板引擎会自动忽略被use标签导入block。 为了避免这种情况。你可以在使用use标签的时候,给block重命名
{% extends "base.html.twig" %}
{% use "blocks.html.twig" with sidebar as base_sidebar %}
{% block sidebar %}{% endblock %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}
parent()函数,会自动的搞定block的继承树,如果你在主模板里覆盖了use标签引入进来的block块,而用parent()函数则可以调用被覆盖的那个block内容
{% extends "base.html.twig" %}
{% use "blocks.html.twig" %}
{% block sidebar %}
{{ parent() }}
{% endblock %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}
注意,parent()的内容 其实是blocks.html.twi里的block sidebar的内容。因为继承树是 base.html.twig->blocks.html.twig->本模板
如果你在use标签里给导入的block重命名了,那就可以使用block函数,来代替上面代码中的parent函数所达到的效果
{% extends "base.html.twig" %}
{% use "blocks.html.twig" with sidebar as parent_sidebar %}
{% block sidebar %}
{{ block('parent_sidebar') }}
{% endblock %}
你可以使用任意数量的use标签,如果多个use标签里的block名字存在重复,那么最后use的那个有效。
7-10、spacelsee标签
会删除html标签之间的空白
{% spaceless %}
<div>
<strong>foo</strong>
</div>
{% endspaceless %}
//输出:<div><strong>foo</strong></div>
7-11、autoescape标签
自动转义
{% autoescape true %}
Everything will be automatically escaped in this block
{% endautoescape %}
{% autoescape false %}
Everything will be outputed as is in this block
{% endautoescape %}
{% autoescape true js %}
Everything will be automatically escaped in this block
using the js escaping strategy
{% endautoescape %}
{% autoescape true %}
{{ safe_value|raw }}
{% endautoescape %}
另外,twig里函数的返回值都是安全的比如 macros parent
7-12、raw标签
raw标签,保证区块内的数据不被模板引擎解析。
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
{{ item|raw }}
7-13、flush标签
告诉模板,刷新输出缓存,在内部其实是调用了php的flush函数
{% flush %}
7-14、do 标签
do 标签的作用就像是输出标签一样{{ }},他可以计算一些表达式,区别是不打印出任何东西
{% do 1 + 2 %}
8、表单
{% include 'sidebar.html' %}
9、json_decode 反序列化 返回array
{# data必须是标准的json字串 #}
{{ data|json_decode}}
10、宏里定义公用数据的方法
{% macro test(params) %}
{% set data = {
"a": 1,
"b": "bbb",
"c": {
"d": 1,
"e": 2
}
} %}
{{ data|json_encode|raw }}
{% endmacro test %}
{% set o_data = cgb.test().__toString|json_decode %}
{{ dump(o_data) }}
array:3 [▼
"a" => 1
"b" => "bbb"
"c" => array:2 [▼
"d" => 1
"e" => 2
]
]
网友评论