runopencode/twig-bufferized-template

延迟并重新排序Twig模板部分的执行。

2.0.0 2017-05-03 21:58 UTC

This package is auto-updated.

Last update: 2024-09-17 10:27:36 UTC


README

Packagist Build Status Scrutinizer Code Quality Code Coverage Build Status

SensioLabsInsight

这个库允许您延迟和重新排序Twig模板中某些部分的执行。Twig被设计和实现为以线性、自顶向下的顺序执行其模板代码。在大多数使用场景中,这种行为是所期望的。然而,有些边缘情况要求模板代码的某些部分在相同模板内的其他部分之前执行。

尽管这种边缘情况的要求看起来不自然,但某些用例证明其使用是合理的。以下是一些例子,但不限于:

  • 类似块式CMS CMF系统(如Sonata项目),其中布局包围独立、独立的块的执行,这可能会影响全局HTML页面属性和元素(元数据、javascript和样式表包含、全局错误和闪存消息等)
  • 任何可以影响全局页面属性和元素的Twig includeembed和类似语句。

安装

这个库是框架无关的,这意味着它可以在任何基于Twig的项目中使用,您只需要使用composer安装它:composer require runopencode/twig-bufferized-template

当然,假设您熟悉Twig(请参阅开发者指南),您需要将Twig Bufferized模板扩展注册到您的Twig环境中(注意示例中给出的设置是默认设置)

$settings = [
    'default_execution_priority' => 0,
    'node_visitor_priority' => 10,
    'whitelist' => [ ],
    'blacklist' => [ ],
    'nodes' => [ ],
];
               
$myTwigEnvironment->addExtension(new \RunOpenCode\Twig\BufferizedTemplate\TwigExtension($settings));

如果您对默认设置满意,可以省略扩展构造函数中的设置,或者您可以调整所需的配置参数,因为设置是通过使用array_merge函数解决的。

在Symfony项目中安装库

这个库附带Symfony包,扩展已在服务容器中注册。您需要在您的AppKernel中注册包

class AppKernel extends Kernel 
{
    public function registerBundles()
    {
        $bundles = array(
            [... YOUR BUNDLES...],
            new RunOpenCode\Twig\BufferizedTemplate\Bridge\Symfony\TwigBufferizedTemplateBundle()
        );
            
        return $bundles;
    }
}

如果您对默认扩展配置不满意,可以在您的config.yml中配置扩展(再次提醒,以下示例中显示的是默认配置)

runopencode_twig_bufferized_template:
    node_visitor_priority: 0
    default_execution_priority: 0
    whitelist: []
    blacklist: []
    nodes: []

请注意,扩展可以通过XML配置(首选方式)进行配置,因此您可以使用提供的XML模式

如何使用扩展?

扩展附带预构建的Twig标签{% bufferize [优先级] %}。标签参数优先级是可选的,如果省略,则使用default_execution_priority配置设置中的值。如果您想要重新排列您的Twig模板中某些部分的执行顺序,请使用{% bufferize %}{% endbufferize %}标签将其包裹,示例

<!doctype html>
<html lang="en">
    <head>
        {% block head %}
            <meta charset="UTF-8">
            <title>Twig test</title>
        {% endblock %}

    </head>
    <body>

    {%  bufferize 10 %}

        This is rendered first                        

    {%  endbufferize %}
    
    {% bufferize -10 %}
    
        This is rendered last
            
    {% endbufferize %}
                    
    ..and everything else is rendered in between - if parameter "default_execution_priority" is between (-10, 10)
                    
    </body>
</html>

重要提示:模板的执行在相同的渲染上下文中缓冲(templateblockinclude等)。请注意,每个块都应该被视为包含的模板,因此每个块是独立的渲染上下文。

缓冲现有Twig节点

如果您有一些需要默认缓冲的自定义标签,您可以使用{% bufferize %}{% endbufferize %}标签将其包裹。但是,您可以自动通过配置扩展来默认缓冲您的标签。为了实现这一点,通过添加完全限定类名作为数组键和执行优先级作为数组值来配置扩展参数nodes,示例

run_open_code_twig_bufferized_template:
    nodes: 
        - Full\Qualified\Class\Name\To\My\Node: 50
        - Full\Qualified\Class\Name\To\My\OtherNode: -5

可以提供一个不带优先级的纯字符串数组来指定要缓冲的自定义节点。在这种情况下,这些节点将获得配置的 default_execution_priority 的优先级。缓冲化仅适用于Twig标签。不要用它来缓冲函数或测试。

其他配置参数

  • node_visitor_priority:Twig定义了节点访问者的优先级,它应该在[-10, 10]之间。通过使用值10,缓冲化节点访问者将在转换AST的过程中作为最后一个节点访问者执行,这是期望的行为。但是,如果您需要不同的优先级,您可以在此处进行配置。
  • default_execution_priority:所有缓冲化模板块的默认执行优先级。
  • whitelist:默认情况下,所有模板都将进行分析以进行缓冲化。您可以明确指定哪些模板应该由节点访问者处理,其他将被忽略。
  • blacklist:此参数与whitelist相反,在此您可以指定哪些模板应该被忽略。您可以使用whitelistblacklist,但不能同时使用。
  • nodes:将其他自定义Twig标签节点添加到模板缓冲化中。

缓冲化是如何工作的?

一般来说,对于每个需要缓冲化的Twig模板(包含{% bufferize %}标签或一些配置的缓冲化自定义节点),每个Twig模板段都被闭包包装,将模板逻辑放置在绑定到当前Twig模板类并可以通过引用访问$blocks$context变量的匿名函数中。

BufferManager具有提到的闭包引用,按执行优先级排序。在块代码结束时,BufferManager首先根据其优先级执行闭包,然后按照先入先出的顺序(如Twig实现)输出它们。

使用缓冲化的缺点是什么?

内存!缓冲化使用ob_start()ob_get_clean()PHP函数,因此每个模板首先存储在内存中,然后刷新。您可以预期内存使用量会有一些轻微的增加——但这取决于您模板的复杂性。请注意,内存使用量的增加不会达到GB级别,而更像几KB,或者几十KB...

给我一个愚蠢的例子,说明何时以及为什么我应该使用这个扩展?

这是一个针对Symfony框架的简单示例。模板将通过使用在模板中渲染控制器的能力来包含部分逻辑。该控制器可以设置一些全局闪存变量,例如“您的账户上没有钱”,该消息应显示在布局的顶部。但是,如果我们按从上到下的顺序执行Twig模板,警告将在执行所需控制器之前渲染,消息将不会显示。

通过使用{% bufferize %}标签,我们可以重新排序模板执行堆栈,并获得所需的结果。

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Twig test</title>
    </head>
    <body>
        {% if app.session.flashbag.get('error') %}
            <div class="alert alert-error">
                {{ app.session.flashbag.get('notice') }}
            </div>
        {% endif %}

    This is my code that I render in my template
    
    {% bufferize 10 %}
    
        {{ render(controller('MyBundle:Article:someController')) }}            
            
    {% endbufferize %}
    
    </body>
</html>

当然,也可以使用其他方法达到相同的结果,例如通过客户端的JavaScript。然而,缓冲化也是一种选项。

要实现这一点并不容易,如果您熟悉Sonata项目,请参阅:Sonata基础布局,注意{{sonata_block_include_stylesheets('screen', app.request.basePath)}}在底部——样式表没有在它们应该的地方加载——在HEAD标签中。

缓冲化可以为Sonata项目(或任何其他类似块型的CMS CMF)提供适当的HTML输出,并完全分离与资产管理相关的单个块逻辑。