嫩枝

灵活、快速、安全
PHP模板引擎

Sy欧宝娱乐app下载地址mfony产品
文档 食谱
您正在阅读Twig 3.x的文档。欧宝体育电话切换到Twig的文档欧宝体育电话1.倍2.倍

食谱

显示弃用通知

已弃用的特性会生成弃用通知(通过调用trigger_error ()PHP函数)。默认情况下,它们是静音的,永远不会显示或记录。

要从模板中删除所有不推荐的功能,请编写并运行如下所示的脚本:

1 2 3 4 5 6 7
require_once__DIR__“/供应商/ autoload.php”嫩枝= create_your_twig_env ();的用法\树枝\ Util \ DeprecationCollector (嫩枝);print_r (的用法->collectDir (__DIR__“/模板”));

collectDir ()方法编译目录中找到的所有模板,捕获弃用通知并返回它们。

提示

如果模板没有存储在文件系统中,请使用收集()方法相反。收集()需要一个可否认的它必须返回模板名称作为键和模板内容作为值(由\树枝\ Util \ TemplateDirIterator).

然而,这段代码不会找到所有的弃用(就像使用一些已弃用的Twig类一样)。为了捕获所有的通知,注册一个自定义错误处理程序,如下所示:

1 2 3 4 5 6 7 8 9 10
的用法= [];set_error_handler (函数类型味精使用(&的用法如果(E_USER_DEPRECATED = = =类型) {的用法[] =味精;}});//运行应用程序print_r (的用法);

注意,大多数弃用通知都是在此期间触发的编译,因此当模板已经缓存时不会生成它们。

提示

如果您想管理来自PHPUnit测试的弃用通知,请查看欧宝娱乐app下载地址symfony / phpunit-bridge软件包,这简化了过程。

使布局有条件

使用Ajax意味着相同的内容有时按原样显示,有时用布局进行装饰。由于Twig布局模板名称可以是任何有效的表达式,您可以传递一个变量,该变量的值为真正的当通过Ajax发出请求时,选择相应的布局:

1 2 3 4 5
{%扩展请求。ajax吗?"base_ajax.html": "base.html" %}{%内容%}这就是要显示的内容。{%endblock%}

使Include动态

当包含一个模板时,它的名称不需要是字符串。例如,名称可以依赖于变量的值:

1
{%包括Var ~ '_foo.html' %}

如果var计算结果为指数,index_foo.html模板将被呈现。

事实上,模板名可以是任何有效的表达式,例如:

1
{%包括var |默认的('index') ~ '_foo.html' %}

重写一个也扩展自身的模板

模板有两种自定义方式:

  • 继承:模板扩展父模板并覆盖一些块;
  • 更换:如果你使用文件系统加载器,Twig加载它在配置目录列表中找到的第一个模板;在目录中找到的模板替换另一个来自列表中更远的目录。

但如何将两者结合起来呢?取代一个模板,也扩展自己(又名模板在目录中进一步的列表)?

假设你的模板都是从这两个地方加载的…/模板/ mysite而且…/模板/违约按这个顺序。的page.twig模板,存储在…/模板/违约全文如下:

1 2 3 4 5
{#页面。树枝#}{%扩展”布局。树枝“%}{%内容%}{%endblock%}

您可以通过放入同名文件来替换此模板…/模板/ mysite.如果您想扩展原始模板,您可能会编写以下代码:

1 2
{#页面。嫩枝in .../templates/mysite #}{%扩展”页面。嫩枝" %}{# from…/模板/违约#}

然而,这将不起作用,因为Twig将始终从加载模板…/模板/ mysite

事实证明,这是可以实现的,只需在模板目录的末尾添加一个目录,它是所有其他目录的父目录:…/模板在我们这里。这使得系统中的每个模板文件都可以唯一寻址。大多数情况下,你会使用“普通”路径,但在特殊情况下,想要扩展一个覆盖模板本身的版本,我们可以在extends标签中引用它的父模板的完整的、明确的模板路径:

1 2
{#页面。嫩枝in .../templates/mysite #}{%扩展“默认/页面。树枝“%}{# from…/模板#}

请注意

这个食谱的灵感来自以下Django wiki页面:https://code.djangoproject.com/wiki/ExtendingTemplates

自定义语法

Twig允许对块分隔符进行一些语法定制。这是建议使用此功能,因为模板将与您的自定义语法绑定。但是对于特定的项目,更改默认值是有意义的。

要更改块分隔符,您需要创建自己的lexer对象:

1 2 3 4 5 6 7 8 9
嫩枝\树枝\环境(…);词法分析程序、树枝、词法分析程序(嫩枝, (“tag_comment”= > [“{#”“#}”),“tag_block”= > [{%的“%}”),“tag_variable”= > [“{{”‘}}),“插值”= > [“#{”“}”)));嫩枝->setLexer (词法分析程序);

下面是一些模拟其他模板引擎语法的配置示例:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
// Ruby erb语法词法分析程序、树枝、词法分析程序(嫩枝, (“tag_comment”= > [“< % #”' % >),“tag_block”= > [“< %”' % >),“tag_variable”= > [“< % =”' % >)));// SGML注释语法词法分析程序、树枝、词法分析程序(嫩枝, (“tag_comment”= > [“< !--#'“- >”),“tag_block”= > [“< !——”“- >”),“tag_variable”= > [“${”“}”)));//聪明的喜欢词法分析程序、树枝、词法分析程序(嫩枝, (“tag_comment”= > [“{*”“*}”),“tag_block”= > [“{”“}”),“tag_variable”= > [‘{$’“}”)));

使用动态对象属性

当Twig遇到一个变量article.title,它试图找到一个标题香港的公共财产文章对象。

如果属性不存在,而是动态定义的,它也可以工作__get ()方法;还需要实现__isset ()Magic方法如下面的代码片段所示:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
文章公共函数__get的名字如果“标题”= =的名字) {返回“标题”;}//抛出某种错误公共函数__isset的名字如果“标题”= =的名字) {返回真正的;}返回;}}

在嵌套循环中访问父上下文

有时,在使用嵌套循环时,需要访问父上下文。类始终可以访问父上下文loop.parent变量。例如,如果你有以下模板数据:

1 2 3 4 5 6
数据= (“主题”= > [“人类”= > [“主题1的信息1”“主题1的信息2”),“话题二”= > [“主题2的信息1”“主题2的信息2”],],];

和下面的模板显示所有主题中的所有消息:

1 2 3 4 5 6
{%Topic, Topic %}中的消息{{循环。指数}}{{topic}}{%messages %}中的消息-{{循环。.loop。指数}}{{循环。指数}}{{message}}{%endfor%}{%endfor%}

输出将类似于:

1 2 3 4 5 6
* 1: topic1 - 1.1:主题1的消息1 - 1.2:主题1的消息2 * 2:topic2 - 2.1:主题2的消息1 - 2.2:主题2的消息2

在内循环中,loop.parent变量用于访问外部上下文。这是电流的指标主题在外部for循环中定义的loop.parent.loop.index变量。

动态定义未定义的函数、过滤器和标签

3.2

registerUndefinedTokenParserCallback ()方法在Twig 3.2中添加。

当一个函数/过滤器/标签没有定义时,Twig默认抛出一个\ \ SyntaxError树枝\错误例外。但是,它也可以调用回调(任何有效的PHP可调用对象),返回函数/过滤器/标记。

对于标记,用寄存器回调registerUndefinedTokenParserCallback ().对于过滤器,用寄存器回调registerUndefinedFilterCallback ().对于函数,请使用registerUndefinedFunctionCallback ()

1 2 3 4 5 6 7 8 9
//自动注册所有原生PHP函数为Twig函数//永远不要在项目中这样做,因为它不安全嫩枝->registerUndefinedFunctionCallback (函数的名字如果(function_exists (的名字)) {返回\树枝\ TwigFunction (的名字的名字);}返回;});

如果可调用对象不能返回有效的函数/过滤器/标记,则必须返回

如果你注册了多个回调,Twig将依次调用它们,直到其中一个没有返回

提示

由于函数/过滤器/标记的解析是在编译期间完成的,所以注册这些回调时没有开销。

验证模板语法

当模板代码由第三方提供时(例如通过web界面),在保存模板之前验证模板语法可能会很有趣。如果模板代码存储在美元的模板变量,你可以这样做:

1 2 3 4 5 6 7
试一试嫩枝->解析(嫩枝->tokenize (\树枝\源(模板)));// $template是有效的(\ \ SyntaxError树枝\错误e) {// $template包含一个或多个语法错误

方法迭代一组文件时,可以将文件名传递给标记()方法获取异常消息中的文件名:

1 2 3 4 5 6 7 8 9
foreach文件作为文件) {试一试嫩枝->解析(嫩枝->tokenize (\树枝\源(模板文件->getFilename (),文件)));// $template是有效的(\ \ SyntaxError树枝\错误e) {// $template包含一个或多个语法错误}}

请注意

这个方法不会捕获任何违反沙盒策略的行为,因为该策略是在模板呈现期间强制执行的(因为Twig需要上下文来进行一些检查,比如对象上允许的方法)。

启用OPcache时刷新修改的模板

当使用OPcache with时opcache.validate_timestamps设置为0, Twig缓存启用和自动重载禁用,清除模板缓存不会更新缓存。

为了解决这个问题,强制Twig使字节码缓存无效:

1 2 3 4
嫩枝\树枝\环境(加载程序, (“缓存”= >缓存\树枝\ \ FilesystemCache (“/一些/缓存/路径”, \树枝\ \ FilesystemCache缓存::FORCE_BYTECODE_INVALIDATION),/ /……]);

重用有状态节点访问者

将访问者附加到\树枝\环境例如,Twig使用它来访问所有它编译模板。如果需要保留一些状态信息,则可能需要在访问新模板时重置它。

这可以通过以下代码实现:

12 3 4 5 6 7 8 9 10 11 12 13
受保护的someTemplateState= [];公共函数enterNode(\ \树枝\节点节点, \树枝\环境env如果节点运算符\ \树枝\节点ModuleNode) {//当我们进入一个新模板时重置状态->someTemplateState = [];}/ /……返回节点;}

使用数据库存储模板

如果您正在开发CMS,模板通常存储在数据库中。这个配方为您提供了一个简单的PDO模板加载器,您可以将其作为自己的模板加载器的起点。

首先,让我们在内存中创建一个临时的SQLite3数据库来使用:

1 2 3 4 5 6 7 8 9 10
胸径PDO (的sqlite::内存:);胸径->exec (创建表模板(名称字符串,源字符串,last_modified INTEGER));基地'{% block内容%}{% endblock %}'指数'{%扩展' base。树枝“%}{%块内容%}Hello {{ name }}{% endblock %} '现在= ();胸径->准备('INSERT INTO templates (name, source, last_modified) VALUES (?, ?, ?)'->执行([“base.twig”基地现在]);胸径->准备('INSERT INTO templates (name, source, last_modified) VALUES (?, ?, ?)'->执行([“index.twig”指数现在]);

我们创建了一个简单的模板表中包含两个模板:base.twig而且index.twig

现在,让我们定义一个能够使用这个数据库的加载器:

12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
DatabaseTwigLoader实现了嫩枝加载程序LoaderInterface受保护的胸径公共函数__construct(PDO胸径->胸径=胸径;}公共函数getSourceContext(字符串的名字如果= = =->getValue (“源”的名字)) {\树枝\错误\ LoaderError (sprintf (“模板“%s”不存在。”的名字));}返回\树枝\源(的名字);}公共函数存在(字符串的名字返回的名字= = =->getValue (“名字”的名字);}公共函数getCacheKey(字符串的名字字符串返回的名字;}公共函数isFresh(字符串的名字, int时间保龄球如果= = =lastModified->getValue (“last_modified”的名字)) {返回;}返回lastModified< =时间;}受保护的函数getValue的名字某事->胸径->准备(“选择”从模板WHERE name =:name);某事->执行([”:“= >(字符串)的名字]);返回某事->fetchColumn ();}}

最后,这里有一个如何使用它的例子:

1 2 3 4
加载程序DatabaseTwigLoader (胸径);嫩枝\树枝\环境(加载程序);回声嫩枝->呈现(“index.twig”, (“名字”= >“法”]);

使用不同的模板源

这个食谱是上一个食谱的延续。即使您将提供的模板存储在数据库中,您也可能希望在文件系统中保留原始/基本模板。可以从不同来源加载模板时,需要使用\树枝\装载机\ ChainLoader加载程序。

正如您在前面的菜谱中看到的,我们引用模板的方式与使用常规文件系统加载器时完全相同。这是能够混合和匹配来自数据库、文件系统或任何其他加载器的模板的关键:模板名应该是一个逻辑名称,而不是来自文件系统的路径:

1 2 3 4 5 6 7 8 9
loader1DatabaseTwigLoader (胸径);loader2\树枝\装载机\ ArrayLoader ([“base.twig”= >'{% block内容%}{% endblock %}']);加载程序\树枝\装载机\ ChainLoader ([loader1loader2]);嫩枝\树枝\环境(加载程序);回声嫩枝->呈现(“index.twig”, (“名字”= >“法”]);

既然base.twigTemplates是在一个数组加载器中定义的,你可以从数据库中删除它,其他的一切仍然会像以前一样工作。

从字符串中加载模板

方法从模板加载存储在字符串中的模板template_from_string函数(通过\树枝\ \ StringLoaderExtension延伸扩展):

1
{{包括(template_from_string("Hello {{name}}"))}}

在PHP中,也可以通过via加载存储在字符串中的模板\树枝\环境::createTemplate ()

1 2
模板嫩枝->createTemplate ('hello {{name}}');回声模板->呈现([“名字”= >“法”]);

在相同的模板中使用Twig和AngularJS

在同一个文件中混合使用不同的模板语法并不推荐,因为AngularJS和Twig在语法中使用了相同的分隔符:{{而且}}

不过,如果你想在同一个模板中使用AngularJS和Twig,有两种方法可以让它工作,这取决于你需要在模板中包含的AngularJS的数量:

  • 元素来包装AngularJS的section,从而转义AngularJS的分隔符{% verbatim %}标记或通过转义每个分隔符{{' {{'}}而且{{'}}'}}
  • 更改其中一个模板引擎的分隔符(取决于您上次引入的引擎):

    • 对于AngularJS,使用interpolateProvider服务,例如在模块初始化时:

      角。module('myApp', []).config(function($interpolateProvider) {
      美元interpolateProvider.startSymbol (' {[') .endSymbol ()});

      });

    • 控件更改分隔符tag_variable词法分析程序的选项:

      1 2 3
      env->setLexer (、树枝、词法分析程序(env, (“tag_variable”= > [”{['']}’)));
网站由欧宝娱乐app下载地址和树枝,部署在
的树枝标志©2010-2023欧宝娱乐app下载地址