1

情况如下:

{% for entry in entries %}
{{ action('entry_modify', entry) }}
{{ entry.title }}
{% endfor %}

action($action, $params) 方法是某种触发器,用于为自己注册一个动作的插件。在这种情况下,我调用“entry_modify”操作,插件使用“entry”参数响应此操作,该参数是一个数组。

function plugin(&$params)
{
    $params['title'] = 'changed to ...'; 
}

但据我了解,Twig 不会通过引用传递变量,有没有办法做到这一点?

我想要的只是修改传递给动作函数的变量。

谢谢...

4

3 回答 3

1

Twig 函数总是通过引用传递对象。您可能会考虑使用对象而不是数组来表示每个条目。

于 2014-01-06T20:33:01.793 回答
1

对于你的问题,我可能有一个解决方案。我正在用 Twig 开发一个 Wordpress 主题,我想通过引用传递变量并向它们添加一些数据。我的目标是制作这样的东西

{{ load_data('all_posts',foo) }}

我想执行一个名为的函数并将load_all_posts该函数的结果分配给foo(我作为第二个参数传递的树枝变量)。我也希望以下内容也可以工作:

{% set foo = {'bar':'bar'} %}

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

{{load_data('all_posts',foo.posts)}}

{#foo is#}
array(2) {
  ["bar"]=>
  string(3) "bar"
  ["posts"]=>
  array(3) {
    [0]=>
    string(5) "post1"
    [1]=>
    string(5) "post2"
    [2]=>
    string(5) "post3"
  }
}

因为并非所有变量都通过引用传递给函数。我们不能为此目的使用函数。相反,我创建了自己的标签并像这样使用它:

{% set foo = {'bar':'bar'} %}
{% load all_pots in foo.posts %}

要做到以下几点,我们必须做两件事:

  • 创建“加载”令牌
  • 调用正确的函数并将数据加载到正确的位置

创建令牌解析器:

令牌的创建很容易。我们只需要告诉 twig 如何使用以下类解析这个标记:

class Load_Data_TokenParser  extends Twig_TokenParser
{
    public function parse(Twig_Token $token)
    {
        $stream = $this->parser->getStream();
        $variable_array = array(); //an array where we'll store the destination variable, as it can be just foo or foo.post, or foo.bar.foo.bar.posts

        $function_name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();  //here we say that we expect a name. In our case it'll be 'all_posts' (the name of the function we will execute)
        $in = $stream->expect(Twig_Token::OPERATOR_TYPE)->getValue();   //here we say that the next thing should be the operator 'in'
        while(Twig_Token::typeToEnglish($stream->getCurrent()->getType()) === 'name'){ //and with this while, we get all the variable names that are separated with '.'
            array_push($variable_array,$stream->getCurrent()->getValue());

            $stream->next();
            $new  = $stream->getCurrent();

            if(Twig_Token::typeToEnglish($new->getType()) === 'punctuation'){
                $stream->next();
            } else {
                break;
            }
        }
        //in our case $variable_array here will be ['foo','posts']

        $stream->expect(Twig_Token::BLOCK_END_TYPE);

        return new Load_Node($variable_array, $function_name, $token->getLine(), $this->getTag());
    }

    public function getTag()
    {
        return 'load';
    }
}

最后,我们返回一个新的“Load_Node”并将其传递$variable_array, $function_name给行和当前标签。

加载数据

class Load_Node extends Twig_Node
{
    public function __construct($variable_array, $function_name, $line, $tag = null)
    {
        $value = new Twig_Node();
        parent::__construct(array('value'=>$value),array(
            'variable_array'=>$variable_array,
            'function_name'=>$function_name
        ),$line,$tag);
    }

    public function compile(Twig_Compiler $compiler)
    {
        $variable_access_string = '';
        $variable_array = $this->getAttribute('variable_array');
        foreach ($variable_array as $single_variable) {
            $variable_access_string.= '[\''.$single_variable.'\']';
        } //here we prepare the string that will be used to access the correct variables. In our case here $variable_access_string will be "['foo']['posts']"

        $compiler
            ->addDebugInfo($this)
            ->write('$context'.$variable_access_string.' = load_'.$this->getAttribute('function_name').'()')
            ->raw(";\n"); //and the here we call load_{function_name} and assign the result to the correct variable
    }
}

目前它仅适用于数组。如果您尝试在对象内加载数据,则会引发异常。稍后我将对其进行编辑并添加对对象的支持。我希望这会帮助你和其他人。祝你今天过得愉快 :)

于 2016-01-08T13:48:38.897 回答
0

If you replace your associative array by a simple class instance you're just fine.

class Entry {
    public $title;
    // other properties possible
    __construct($title) {
        $this->title = $title
    }
}

then your $entries would be an array of Entry instances that will be passed as reference to any function because it's an object, not an array. Your original twig code snippet would be fine then (perfect syntax), and would modify the title.

于 2021-10-20T15:45:59.327 回答