是否可以在Twig中在布局文件中设置自动窗口策略

时间:2017-12-29 10:30:35

标签: php symfony twig

我有一个Javascript数组中有{% block content %}{% endblock %}的布局文件,如下所示

<script type="text/javascript">
    cols:[
            {% block content %}{% endblock %}
        ];
</script>

然后在许多使用这样的布局文件的模板中进行扩展(真正的模板有更多的代码和变量行):

{% block content %}
    { view:"text", name:"visitDate", value:"{{ date }}", label:"Date/Time:", labelWidth:100, width:285, labelAlign:"right", readonly:true },
{% endblock %}

由于content块总是需要使用“js”策略进行转义,有没有办法在布局模板中指定这个我累了:

<script type="text/javascript">
    cols:[
            {% autoescape 'js' %}
                {% block content %}{% endblock %}
            {% endautoescape %} 
        ];
</script>

但这似乎不起作用,并且在Twig文档中找不到任何示例。如果我在模板中的autoescape块内添加content块,我可以使它工作,但这不是正确的方法。

例如,使用上面的代码,应将以下HTML / Javascript发送到浏览器{{ date }} =“17/12/2017 15:01:53”:

<script type="text/javascript">
    cols:[
            { view:"text", name:"visitDate", value:"17\x2F12\x2F2017\x2015\x3A01\x3A53", label:"Date/Time:", labelWidth:100, width:285, labelAlign:"right", readonly:true },
        ];
</script>

只有子模板content块中的模板变量才能转义,而不是实际的Javascript代码,如果您使用{{ block('content')|e('js') }}行的内容,则会获得该代码。

1 个答案:

答案 0 :(得分:0)

我能想到的一个解决方案是创建节点访问者类,它将处理每个树枝节点,并根据块名称应用相应的转义策略。

  1. 首先create custom twig extension
  2. 创建节点访问者对象,该对象将在开始和结束content
  3. 之间将转义策略应用于每个节点
  4. 在扩展名中注册节点vistor。
  5. 以下是一个示例访问者,它将在js块内的每个print节点上content转义过滤器:

    <?php
    
    declare(strict_types=1);
    
    namespace App\Twig;
    
    class AppExtension extends \Twig_Extension
    {
        /**
         * {@inheritdoc}
         */
        public function getNodeVisitors()
        {
            /**
             * Node visitor that applies `js` escaping strategy to every output node under `content` block
             *
             * @var \Twig_NodeVisitorInterface
             */
            $visitor = new class() implements \Twig_NodeVisitorInterface {
                /**
                 * @var bool
                 */
                private $escape = false;
    
                /**
                 * {@inheritdoc}
                 */
                public function enterNode(\Twig_Node $node, \Twig_Environment $env)
                {
                    // Start of `content` block found, set `escape` to true to indicate that next nodes should be escaped
                    if ($this->isContentBlockNode($node)) {
                        $this->escape = true;
                    }
    
                    return $node;
                }
    
                /**
                 * {@inheritdoc}
                 */
                public function leaveNode(\Twig_Node $node, \Twig_Environment $env)
                {
                    if ($node instanceof \Twig_Node_Module) {
                        $this->escape = false;
                    }
    
                    if ($this->escape) {
                        if ($node instanceof \Twig_Node_Print) {
                            $expr = $node->getNode('expr');
                            // Skipping if escape strategy provided in the template for this node
                            if ($expr instanceof \Twig_Node_Expression_Filter) {
                                return $node;
                            }
    
                            $line = $expr->getTemplateLine();
                            $name = new \Twig_Node_Expression_Constant('escape', $line);
                            $args = new \Twig_Node(array(new \Twig_Node_Expression_Constant('js', $line), new \Twig_Node_Expression_Constant(null, $line), new \Twig_Node_Expression_Constant(true, $line)));
    
                            $filter = new \Twig_Node_Expression_Filter($expr, $name, $args, $line);
    
                            $class = get_class($node);
    
                            return new $class($filter, $node->getTemplateLine());
                        }
                    }
    
                    // End of `content` block, disable escape policy for further nodes
                    if ($this->isContentBlockNode($node)) {
                        $this->escape = false;
                    }
    
                    return $node;
                }
    
                /**
                 * {@inheritdoc}
                 */
                public function getPriority()
                {
                    return -10;
                }
    
                /**
                 * Checks whether the node is `content` block
                 *
                 * @param \Twig_Node $node
                 *
                 * @return bool
                 */
                private function isContentBlockNode(\Twig_Node $node): bool
                {
                    return ($node instanceof \Twig_Node_Block && 'content' === $node->getAttribute('name'));
                }
            };
    
            return [$visitor];
        }
    }