Twig 方法
原文:Recipes 翻译:小虾米(QQ:509129)
Recipes
显示的通知
弃用特性生成弃用通知(通过调用trigger_error()PHP函数)。默认情况下,它们是静默的,不会显示,也不会记录。
为了方便地从模板中删除所有已弃用的特性用法,请在下面的代码行中编写和运行一个脚本:
require_once __DIR__.'/vendor/autoload.php';
$twig = create_your_twig_env();
$deprecations = new Twig_Util_DeprecationCollector($twig);
print_r($deprecations->collectDir(__DIR__.'/templates'));collectDir()方法编译目录中找到的所有模板,捕获弃用通知,并返回它们。
如果模板不存储在文件系统中,则使用collect()方法。collect()接受一个可遍历,它必须返回模板名称作为键,模板内容作为值(如Twig_Util_TemplateDirIterator)。
但是,这段代码不会找到所有的弃用(比如使用不赞成的一些Twig类)。要捕获所有通知,请注册一个类似下面的错误处理程序:
require_once __DIR__.'/vendor/autoload.php';
$twig = create_your_twig_env();
$deprecations = new Twig_Util_DeprecationCollector($twig);
print_r($deprecations->collectDir(__DIR__.'/templates'));注意,在编译过程中会触发大多数的弃用通知,所以当模板已经被缓存时,它们不会生成。
如果您想从您的PHPUnit测试中管理弃用通知,请查看一下symfony / PHPUnit - bridge包,这将极大地简化过程。
做一个布局条件(Making a Layout conditional)
使用Ajax意味着相同的内容有时会显示为is,有时还会以布局来装饰。当Twig布局模板名称可以是任何有效的表达式时,您可以通过Ajax传递一个评估为true的变量,并据此选择布局:
做一个动态包含(Making an Include dynamic)
当包含模板时,它的名称不需要是字符串。例如,名称可以依赖于变量的值:
如果var的值是index,则是index_foo。将呈现html模板。
事实上,模板名称可以是任何有效的表达式,例如以下内容:
重写一个扩展自身的模板(Overriding a Template that also extends itself)
模板可以以两种不同的方式定制:
继承:模板扩展了父模板,覆盖了一些块;
替换:如果您使用文件系统加载程序,Twig将加载在已配置目录列表中发现的第一个模板;在目录中发现的模板将从列表中进一步的目录中替代另一个模板。
但是,如何将二者结合在一起:替换一个扩展自身的模板(在目录中进一步的目录中)?
让我们假设您的模板从两个都加载../templates/mysite和.../templates/default按此顺序。该页面。将模板存储在.../templates/default读取模板如下:
您可以通过在 .../templates/mysite中放入相同名称的文件来替换这个模板。如果您想扩展原始模板,您可能会尝试编写以下内容:
当然,这不会起作用,因为Twig总是从.../templates/mysite 加载模板。
事实证明,这是可能的工作,通过添加一个目录在您的模板目录,这是所有其他目录的父目录:.../templates在我们的例子。这使得我们的系统中的每个模板文件唯一的寻址。大多数情况下,你将使用“正常”的路径,但在特殊情况下,要扩展的模板与压倒一切的版本本身,我们可以引用其父的完整,明确的模板路径的扩展标签:
这个recipe灵感来自以下Django wiki页面:http://code.djangoproject.com/wiki/extendingtemplatez
自定义语法(Customizing the Syntax)
Twig允许对块分隔符进行一些语法定制。不推荐使用此特性作为模板将与您的自定义语法绑定。但是对于特定的项目,更改默认值是有意义的。
要更改块分隔符,您需要创建自己的lexer对象:
下面是一些模拟其他模板引擎语法的配置示例:
使用动态对象属性(Using dynamic Object Properties)
当Twig遇到像 article.title 这样的变量时,它试图在article对象中找到一个title公共属性。
如果属性不存在,它也可以工作,但是由于魔术方法__get()方法动态地定义了属性,您只需要执行如下代码片段所示的__isset()魔术方法:
在嵌套循环中访问父级上下文(Accessing the parent Context in Nested Loops)
有时,当使用嵌套循环时,您需要访问父级上下文。父上下文始终可以通过循环访问。父类变量。例如,如果您有以下模板数据:
下面的模板将显示所有主题中的所有消息:
输出:
在内部循环中,loop.parent变量用于访问外部上下文。因此,在外部for循环中定义的当前topic的索引是通过 loop.parent.loop.index 变量。
定义未定义的函数和过滤器(Defining undefined Functions and Filters on the Fly)
当没有定义函数(或过滤器)时,Twig默认会抛出Twig_Error_Syntax异常。但是,它也可以调用回调(任何有效的PHP调用),它应该返回一个函数(或过滤器)。
对于筛选器,使用registerUndefinedFilterCallback()注册回调。对于函数,使用registerUndefinedFunctionCallback():
如果callable无法返回有效的函数(或过滤器),则必须返回false。
如果您注册多个回调,Twig将依次调用它们,直到其中一个不返回false。
由于函数和过滤器的解析是在编译期间完成的,所以在注册这些回调时没有开销。
验证模板语法(Validating the Template Syntax)
当模板代码由第三方提供时(例如通过web接口),在保存模板语法之前,验证模板语法可能会很有趣。如果模板代码存储在$template变量中,那么您可以这样做:
如果您对一组文件进行迭代,可以将文件名传递给tokenize()方法以获取异常消息中的文件名:
此方法不会捕获任何沙箱策略违规,因为在模板呈现期间执行策略(当Twig需要上下文来进行一些检查,比如对象允许的方法)。
启用OPcache或APC时刷新修改的模板(Refreshing modified Templates when OPcache or APC is enabled)
在使用OPcache时使用opcache.validate_timestamps设置为0或APC的apc.stat设置为0并启用Twig缓存,清除模板缓存不会更新缓存。
为了解决这个问题,强制Twig使字节码缓存失效:
重用有状态的节点访问者(Reusing a stateful Node Visitor)
当将访问者附加到Twig_Environment实例时,Twig会使用它来访问它编译的所有模板。如果您需要保留一些状态信息,您可能希望在访问新模板时重新设置它。
这可以很容易地用以下代码实现:
使用数据库存储模板(Using a Database to store Templates)
如果您正在开发CMS,模板通常存储在数据库中。这个配方提供了一个简单的PDO模板加载器,您可以将它用作您自己的起点。
首先,让我们创建一个用于工作的临时内存SQLite3数据库:
我们创建了一个简单的模板表,其中包含两个模板:base.twig 和 index.twig。
现在,让我们定义一个可以使用这个数据库的加载器:
最后,这里有一个关于如何使用它的例子:
使用不同的模板来源(Using different Template Sources)
这个recipe是前一个的延续。即使您将贡献的模板存储在数据库中,您可能希望保留文件系统上的原始/基本模板。当模板可以从不同的源加载时,您需要使用Twig_Loader_Chain加载程序。
正如您在前面的recipe中看到的,我们以完全相同的方式引用模板,就像我们使用常规的文件系统加载程序那样。这是能够混合和匹配来自数据库、文件系统或任何其他加载器的模板的关键:模板名称应该是一个逻辑名称,而不是来自文件系统的路径:
现在 base.twig模板定义在一个数组加载器中,您可以从数据库中删除它,其他所有的内容仍然会像以前那样工作。
从字符串中加载模板(Loading a Template from a String)
从模板中,您可以轻松地通过template_from_string函数(通过Twig_Extension_StringLoader扩展)加载存储在字符串中的模板:
从PHP中,还可以通过Twig_Environment加载存储在字符串中的模板:createTemplate():
在同一个模板中使用Twig和AngularJS(Using Twig and AngularJS in the same Templates)
在同一个文件中混合不同的模板语法并不是一个推荐的做法,因为AngularJS和Twig在语法中使用相同的分隔符: }。
不过,如果您想在同一个模板中使用AngularJS和Twig,有两种方法可以使它工作,这取决于您需要在模板中包含的AngularJS的数量:
从AngularJS分隔符中,通过将AngularJS部分与{% verbatim %}标记或通过{{ '{{' }} 和 {{ '}}' }}来分隔每个分隔符;
更改一个模板引擎的分隔符(取决于您最后引入的引擎)
对于AngularJS,使用插值提供服务来更改插值标记,例如在模块的初始化时间:
对于Twig,通过tag_variable Lexer选项改变分隔符:
Last updated
Was this helpful?