Twig for 开发者

原文:Twig for Developers 翻译:小虾米(QQ:509129)

Twig for 开发者

本章描述了Twig的API,而不是模板语言。这将是最有用的参考对于那些实现模板接口的用户来说,而不是那些创建Twig模板的人来说。

基础知识(Basics)

Twig使用一个名为环境(environment)的中心对象(类Twig_Environment)。该类的实例用于存储配置和扩展,用于从文件系统或其他位置加载模板。

大多数应用程序将在应用程序初始化时创建一个Twig_Environment对象,并将其用于加载模板。在某些情况下,如果使用不同的配置,那么有多个环境并排使用是非常有用的。

配置Twig到加载模板的最简单方法是这样的:

require_once '/path/to/vendor/autoload.php';

$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
    'cache' => '/path/to/compilation_cache',
));

这将创建一个带有默认设置的模板环境和一个加载器,它会查找/ path / to / templates /文件夹中的模板。不同的加载器是可用的,如果想从数据库或其他资源加载模板,也可以编写自己的文件。

注意,环境(environment)的第二个参数是一系列选项。缓存选项是一个编译缓存目录,其中Twig缓存已编译的模板,以避免对次序列请求的解析阶段。它与您可能想要为评估的模板添加的缓存非常不同。对于这样的需求,您可以使用任何可用的PHP缓存库。

渲染模板(Rendering Templates)

要从Twig环境中加载模板,请调用load()方法,该方法返回Twig_TemplateWrapper实例:

$template = $twig->load('index.html');

要使用一些变量来呈现模板,请调用render()方法:

echo $template->render(array('the' => 'variables', 'go' => 'here'));

display()方法是直接输出模板的快捷方式。

您还可以加载并呈现模板一次搞定:

echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here'));

如果模板定义了块,则可以通过renderBlock()调用来单独呈现它们:

echo $template->renderBlock('block_name', array('the' => 'variables', 'go' => 'here'));

环境选项(Environment Options)

当创建一个新的Twig_Environment实例时,可以将一系列选项作为构造函数的第二个参数:

$twig = new Twig_Environment($loader, array('debug' => true));

以下选项可供选择:

  • debug 布尔类型(boolean)

当设置为true时,生成的模板有一个__toString()方法,您可以使用它来显示生成的节点(默认为false)。

  • charset 字符串类型(string)(默认为utf-8)

用于生成模板的基础模板类。

  • cache 字符串类型(string) 或 false

一个绝对路径,用于存储已编译的模板,或者是false来禁用缓存(这是默认的)。

  • auto_reload 布尔类型(boolean)

当使用Twig进行开发时,每当源代码发生变化时重新编译模板是很有用的。如果您不为auto_reload选项提供一个值,那么它将根据调试值自动确定。

  • strict_variables 布尔类型(boolean)

如果设置为false,Twig将静默地忽略无效的变量(不存在的变量和属性/方法),并以null值替换它们。当设置为true时,Twig会抛出一个异常(默认为false)。

  • autoescape 字符串类型(string)

设置默认的自动转义策略(名称、html、js、css、url、html_attr,或一个PHP回调,它接受模板“文件名”并返回转义策略的使用——回调不能是一个函数名,以避免与内置的转义策略发生冲突);设置为false来禁用自动转义。名称逃逸策略决定了基于模板文件名扩展的模板的转义策略(这一策略不会在运行时造成任何开销,因为自动转义是在编译时完成的)。

  • optimizations 整型类型(integer)

一个标志(默认为- 1)的标志(默认为- 1),所有的优化都被启用;将其设置为0来禁用。

加载器(Loaders)

加载程序负责从资源(如文件系统)加载模板。

编译缓存(Compilation Cache)

所有模板加载器都可以在文件系统上缓存已编译的模板,以备将来重用。它加速了Twig的速度,因为模板只编译一次;如果使用APC这样的PHP加速器,性能的提升就会更大。请参阅上面的缓存和auto_reload选项以获得更多信息。

内置的加载器(Built-in Loaders)

下面是内置的loaders Twig提供的列表:

Twig_Loader_Filesystem

Twig_Loader_Filesystem从文件系统加载模板。这个加载器可以在文件系统的文件夹中找到模板,并且是加载它们的首选方法:

$loader = new Twig_Loader_Filesystem($templateDir);

它还可以在一系列目录中寻找模板:

$loader = new Twig_Loader_Filesystem(array($templateDir1, $templateDir2));

有了这样的配置,Twig将首先在$ templateDir1中寻找模板,如果它们不存在,那么它就会在$ templateDir2中寻找它们。

您可以通过addPath()和prependPath()方法添加或prepend路径:

$loader->addPath($templateDir3);
$loader->prependPath($templateDir4);

文件系统加载器还支持名称空间模板。这允许在有自己的模板路径的不同名称空间中对模板进行分组。

当使用setpath()、addPath()和prependPath()方法时,将名称空间指定为第二个参数(当未指定时,这些方法将在“main”命名空间上执行):

$loader->addPath($templateDir, 'admin');

名称空间模板可以通过特殊的@ namespace_name / template_path符号来访问:

$twig->render('@admin/index.html', array());

Twig_Loader_Filesystem支持绝对和相对路径。使用相对路径是首选的,因为它使缓存键独立于项目根目录(例如,它允许从构建服务器中缓存缓存,其中目录可能与生产服务器上使用的目录不同):

$loader = new Twig_Loader_Filesystem('templates', getcwd().'/..');

当没有将根路径作为第二个参数传递时,Twig会使用getcwd()相对路径。

Twig_Loader_Array

Twig_Loader_Array从一个PHP数组加载一个模板。它传递了绑定到模板名称的字符串数组:

$loader = new Twig_Loader_Array(array(
    'index.html' => 'Hello {{ name }}!',
));
$twig = new Twig_Environment($loader);

echo $twig->render('index.html', array('name' => 'Fabien'));

这个加载器对于单元测试非常有用。它还可以用于小型项目,其中将所有模板存储在一个PHP文件中可能是有意义的。

当使用带有缓存机制的数组加载程序时,您应该知道每当模板内容“变化”(缓存键是模板的源代码)时,都会生成一个新的缓存键。如果您不想看到缓存失控,您需要自己处理旧的缓存文件。

wig_Loader_Chain

Twig_Loader_Chain将模板加载到其他加载器:

$loader1 = new Twig_Loader_Array(array(
    'base.html' => '{% block content %}{% endblock %}',
));
$loader2 = new Twig_Loader_Array(array(
    'index.html' => '{% extends "base.html" %}{% block content %}Hello {{ name }}{% endblock %}',
    'base.html'  => 'Will never be loaded',
));

$loader = new Twig_Loader_Chain(array($loader1, $loader2));

$twig = new Twig_Environment($loader);

在寻找模板时,Twig会依次尝试每个加载器,一旦找到模板,它就会返回。当呈现来自上面例子中的index.htm模板,Twig将用$ loader2加载它,但是base.html模板将从$ loader1加载。

Twig_Loader_Chain接受任何实现Twig_LoaderInterface的加载器。

还可以通过addLoader()方法添加loaders。

创建自己的加载器

所有加载器都实现Twig_LoaderInterface:

interface Twig_LoaderInterface
{
    /**
     * Returns the source context for a given template logical name.
     *
     * @param string $name The template logical name
     *
     * @return Twig_Source
     *
     * @throws Twig_Error_Loader When $name is not found
     */
    public function getSourceContext($name);

    /**
     * Gets the cache key to use for the cache for a given template name.
     *
     * @param string $name The name of the template to load
     *
     * @return string The cache key
     *
     * @throws Twig_Error_Loader When $name is not found
     */
    public function getCacheKey($name);

    /**
     * Returns true if the template is still fresh.
     *
     * @param string    $name The template name
     * @param timestamp $time The last modification time of the cached template
     *
     * @return bool    true if the template is fresh, false otherwise
     *
     * @throws Twig_Error_Loader When $name is not found
     */
    public function isFresh($name, $time);

    /**
     * Check if we have the source code of a template, given its name.
     *
     * @param string $name The name of the template to check if we can load
     *
     * @return bool    If the template source code is handled by this loader or not
     */
    public function exists($name);
}

如果当前缓存的模板仍然是新鲜的,给定了最后的修改时间,或者其他错误,则isFresh()方法必须返回true。

getSourceContext()方法必须返回Twig_Source的一个实例。

使用扩展(Using Extensions)

Twig扩展是将新特性添加到Twig的包。使用扩展很简单就是使用addExtension()方法:

$twig->addExtension(new Twig_Extension_Sandbox());

Twig与以下扩展捆绑在一起:

  • Twig_Extension_Core:定义Twig的所有核心特性。

  • Twig_Extension_Escaper:添加自动输出-转义,以及避免/无法避免代码块的可能性。

  • Twig_Extension_Sandbox:将沙箱模式添加到默认的Twig环境中,从而安全评估不受信任的代码。

  • Twig_Extension_Profiler:启用了内置的Twig分析器。

  • twig_extension_优化:在编译之前优化节点树。

核心、逃避者和优化器扩展不需要添加到Twig环境中,因为它们是默认注册的。

内置扩展(Built-in Extensions)

本节描述内置扩展添加的特性。

阅读关于扩展Twig的章节,了解如何创建自己的扩展。

核心扩展(Core Extension)

核心扩展定义了Twig的所有核心特性:

转义扩展(Escaper Extension)

转义扩展增加了自动输出转义到Twig。它定义了一个标签、autoescape和一个过滤器,raw。

在创建转义扩展时,您可以打开或关闭全局输出转义策略:

$escaper = new Twig_Extension_Escaper('html');
$twig->addExtension($escaper);

如果设置为html,模板中的所有变量都可以通过(使用html转义策略),除非使用raw过滤器:

{{ article.to_html|raw }}

您还可以使用自动转义标签改变本地的转义模式:

{% autoescape 'html' %}
    {{ var }}
    {{ var|raw }}      {# var won't be escaped #}
    {{ var|escape }}   {# var won't be double-escaped #}
{% endautoescape %}

autoescape标签对包含的文件没有影响。

转义规则执行如下:

  • 直接在模板中使用的文本(整数、布尔值、数组等)不会自动转义:

{{ "Twig<br />" }} {# won't be escaped #}

{% set text = "Twig<br />" %}
{{ text }} {# will be escaped #}
  • 结果永远是文字或有标记的安全的表达式不会自动转义:

{{ foo ? "Twig<br />" : "<br />Twig" }} {# won't be escaped #}

{% set text = "Twig<br />" %}
{{ foo ? text : "<br />Twig" }} {# will be escaped #}

{% set text = "Twig<br />" %}
{{ foo ? text|raw : "<br />Twig" }} {# won't be escaped #}

{% set text = "Twig<br />" %}
{{ foo ? text|escape : "<br />Twig" }} {# the result of the expression won't be escaped #}
  • 在打印之前,在其他过滤器被应用后,转义被应用:

{{ var|upper }} {# is equivalent to {{ var|upper|escape }} #}
  • raw过滤器只能在过滤器链的末端使用:

{{ var|raw|upper }} {# will be escaped #}

{{ var|upper|raw }} {# won't be escaped #}

如果链中的最后一个过滤器对于当前上下文(例如html或js)是安全的,则不应用自动转义。escape和escape(“html”)标记为安全的html,escape(“js”)在JavaScript上是安全的,raw是安全的。

{% autoescape 'js' %}
    {{ var|escape('html') }} {# will be escaped for HTML and JavaScript #}
    {{ var }} {# will be escaped for JavaScript #}
    {{ var|escape('js') }} {# won't be double-escaped #}
{% endautoescape %}

注意,自动转义有一些限制,因为转义是在评估后的表达式中应用的。例如,当使用连接时,{ { foo | raw ~ bar } }不会给出预期的结果,因为它是在连接的结果上应用的,而不是在单个变量上(因此,raw 过滤器在这里不会产生任何效果)。

沙箱扩展(Sandbox Extension)

可以使用sandbox扩展来评估不受信任的代码。禁止使用不安全的属性和方法。沙箱安全性由策略实例管理。默认情况下,Twig附带一个策略类:Twig_Sandbox_SecurityPolicy。这个类允许你列出一些标签、过滤器、属性和方法:

$tags = array('if');
$filters = array('upper');
$methods = array(
    'Article' => array('getTitle', 'getBody'),
);
$properties = array(
    'Article' => array('title', 'body'),
);
$functions = array('range');
$policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);

使用前一个配置,安全策略只允许使用if标记和上过滤器。此外,模板只能调用getTitle()和getBody()方法在文章对象上,以及标题和主体公共属性。其他的都不允许,并生成Twig_Sandbox_SecurityError异常。

策略对象是sandbox构造函数的第一个参数:

$sandbox = new Twig_Extension_Sandbox($policy);
$twig->addExtension($sandbox);

默认情况下,sandbox模式是禁用的,当使用sandbox标记包含不受信任的模板代码时,应该启用这个模式:

{% sandbox %}
    {% include 'user.html' %}
{% endsandbox %}

您可以将所有模板都通过true作为扩展构造函数的第二个参数:

$sandbox = new Twig_Extension_Sandbox($policy, true);

分析器扩展(Profiler Extension)

profiler扩展允许对Twig模板进行分析器;它应该只在您的开发机器上使用,因为它增加了一些开销:

$profile = new Twig_Profiler_Profile();
$twig->addExtension(new Twig_Extension_Profiler($profile));

$dumper = new Twig_Profiler_Dumper_Text();
echo $dumper->dump($profile);

一个配置文件包含用于模板、块和宏执行的时间和内存消耗信息。

您还可以将数据转储到Blackfire.io兼容的格式:

$dumper = new Twig_Profiler_Dumper_Blackfire();
file_put_contents('/path/to/profile.prof', $dumper->dump($profile));

上传资料,以使其可视化(先创建一个免费帐户):

blackfire --slot=7 upload /path/to/profile.prof

优化器扩展(Optimizer Extension)

优化器扩展在编译之前优化节点树:

$twig->addExtension(new Twig_Extension_Optimizer());

默认情况下,所有的优化都是打开的。您可以通过将它们传递给构造函数来选择要启用的函数:

$optimizer = new Twig_Extension_Optimizer(Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR);

$twig->addExtension($optimizer);

Twig支持以下优化:

  • Twig_NodeVisitor_Optimizer::OPTIMIZE_ALL,启用所有优化(这是默认值)。

  • Twig_NodeVisitor_Optimizer::OPTIMIZE_NONE,禁用所有优化。这减少了编译时间,但是它可以增加执行时间和内存。

  • Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR,在可能的情况下,通过移除循环变量的创建来优化for标记。

  • Twig_NodeVisitor_Optimizer::OPTIMIZE_RAW_FILTER,尽可能删除raw过滤器。

  • Twig_NodeVisitor_Optimizer::OPTIMIZE_VAR_ACCESS,可以在可能的情况下简化编译时模板中的变量的创建和访问。

异常(Exceptions)

Twig可以抛出异常:

  • Twig_Error:所有错误的基本异常。

  • Twig_Error_Syntax:抛出来告诉用户模板语法有问题。

  • Twig_Error_Runtime:当运行时发生错误时抛出(例如,当一个过滤器不存在时)。

  • Twig_Error_Loader:在模板加载过程中抛出错误。

  • Twig_Sandbox_SecurityError:当一个不允许的标记、过滤器或方法被调用在一个沙盒模板中时抛出。

Last updated