Twig_SimpleFunction可以修改上下文吗?

时间:2015-09-11 13:47:14

标签: php symfony templates twig

是否可以通过调用Twig_SimpleFunction来修改当前的twig上下文?

我注册了以下功能:

<?php
namespace Craft;

class TwiggedTwigExtension extends \Twig_Extension
{
    public function getName()
    {
      return 'Twigged';
    }

    public function getFunctions()
    {
        return array(
            'setContextVar' => new \Twig_SimpleFunction('setContextVar', array($this, 'setContextVar'), array('needs_context' => true)),
        );
    }

    public function setContextVar($context, $str, $val)
    {
        $context['context'][$str] = $val;

        var_dump(array_keys($context['context']));
    }
}

从类似{{ setContextVar('hellow', 'world') }}的模板调用时,var_dump显示修改后的上下文。但是像{{ dump(_context|keys) }}那样快速检查模板并不会显示修改后的上下文。

我是以错误的方式解决这个问题吗?

2 个答案:

答案 0 :(得分:4)

这对于函数是不可能的,因为上下文不是通过引用传递的。

在您的扩展程序中,您甚至访问$context['context'],这意味着名为context的变量,而不是上下文本身(_context是用于访问上下文的特殊变量名称模板,但它没有出现在发送到函数的上下文数组中,因为它是数组本身。)

可能有一种方法可以通过更改节点类来自定义编译函数来执行此操作。但是我没有尝试过,可能最终有点难以维持语义表达 无论如何,我建议不要写这样的功能。在Twig中分配变量没有函数语义,不能作为表达式的一部分完成(函数当然可以在表达式中使用)。改变这种语义可能会导致奇怪的行为。

答案 1 :(得分:2)

与评论中提到的@DarkBee一样,您可以通过引用来修改上下文:

function setContextVar(&$context, ...)

然而,仅向Twig添加一个函数似乎不起作用(我正在使用Twig 2.4.4):

$twig->addFunction(new Twig_Function('setContextVar', function(&$context, $name, $value) {
    $context[$name] = $value;
}, ['needs_context' => true]));

在Twig文件中使用该函数时,上下文不会被修改,并且您收到此警告:

  

警告:参数1到{closure}()应该是一个引用值   在C:\ ... \ vendor \ twig \ twig \ lib \ Twig \ Environment.php(378)中给出:   eval()'代码在线......

相反,您需要创建一个Twig扩展名:

$twig->addExtension(new class extends Twig_Extension {
    public function getFunctions() {
        return [
            new Twig_Function('setContextVar', [$this, 'setContextVar'], ['needs_context' => true]),
        ];
    }

    public function setContextVar(&$context, $name, $value) {
        $context[$name] = $value;
    }
});

然后你可以在Twig中使用它而不会收到警告:

{{ dump() }}
{% do setContextVar('foo', 'bar') %}
{{ dump() }}

以上打印例如:

array(0) {
}

array(1) {
  ["foo"]=>
  string(3) "bar"
}