【问题标题】:Twig iterate over object propertiesTwig 遍历对象属性
【发布时间】:2012-08-07 07:54:34
【问题描述】:

我在 Twig 文档中读到,可以通过以下方式迭代关联数组:

{% for key, value in array %}  
 {{key}}  
 {{value}}  
{% endfor %}  

我想知道这是否也适用于 stdClass 类型的对象。

我本来希望 Twig 以属性名称作为键来迭代对象的属性值。相反,for循环中包含的指令块根本不执行。

【问题讨论】:

  • “它似乎不起作用”是什么意思?
  • @KingCrunch 意思是我尝试的时候没用,但可能是我做错了什么。我对它是否是模板引擎支持的功能感兴趣。为了清楚起见,我将编辑我的消息。
  • @Bodgan 我想问的是:而不是会发生什么? ;)
  • @KingCrunch 它根本不迭代对象的属性,使用我上面提供的语法。
  • @KingCrunch 更准确地说,它只是忽略了构造并继续渲染。它不会引发异常。

标签: php twig


【解决方案1】:

您可以先将对象转换为数组。您可以构建自己的过滤器,将您的对象转换为数组。更多关于过滤器的信息在这里:http://twig.sensiolabs.org/doc/advanced.html#filters

它可能看起来像这样:

{% for key, value in my_object|cast_to_array %}

【讨论】:

  • 感谢您的快速回复,Tadeck。在写这个问题之前,我已经使用了你提出的解决方案。我目前在 PHP 控制器中使用 get_object_vars 将对象转换为数组,但我很好奇 Twig 中是否有一个功能可以让我避免在控制器中处理对象。在这种特殊情况下,期望以与数组相同的方式处理对象似乎是合理的。
  • 我会接受你的回答,因为它至少可以解决问题。
【解决方案2】:

要完成 Tadeck 的回答,方法如下:

如果您从未创建或设置过 Twig 扩展(过滤器),则需要先按照此说明进行操作 http://symfony.com/doc/2.7/cookbook/templating/twig_extension.html

1) 添加到您的 AppBundle/Twig/AppExtension.php ('cast_to_array')

public function getFilters()
{
    return array(
        new \Twig_SimpleFilter('md2html', array($this, 'markdownToHtml'), array('is_safe' => array('html'))),
        new \Twig_SimpleFilter('price', array($this, 'priceFilter')),
        new \Twig_SimpleFilter('cast_to_array', array($this, 'objectFilter')),
    );
}

2) 添加到您的 AppBundle/Twig/AppExtension.php

public function objectFilter($stdClassObject) {
    // Just typecast it to an array
    $response = (array)$stdClassObject;

    return $response;
}

3) 在您的 example.html.twig 循环中使用树枝和过滤器。

{% for key, value in row|cast_to_array %}
       <td id="col" class="hidden-xs">{{ value }}</td>
{% endfor %}

完成,希望对您有所帮助。来自塔德克的指针。

【讨论】:

    【解决方案3】:

    加载 TWIG 后,添加此过滤器:

    $twig->addFilter( new Twig_SimpleFilter('cast_to_array', function ($stdClassObject) {
        $response = array();
        foreach ($stdClassObject as $key => $value) {
            $response[] = array($key, $value);
        }
        return $response;
    }));
    

    根据Tadeck 的建议命名为cast_to_array。 :) 我确信它不适用于任何类型的 stdClass 对象,但它确实解决了我打印 PHP 关联数组 的问题 :) 按如下方式使用它:

    {% for key, value in my_object|cast_to_array %}
        <td>{{ value.1 }}</td>
    {% endfor %}
    

    支线故事

    由于我经常进入这个 SO 页面,我认为有必要展示我在哪里使用 Twig 来迭代对象属性,因此它对其他有同样问题的人很有帮助: 我试图从 .json 源打印表格,但 PHP 的 json_decode 将任何 "key" : "value" 转换为 PHP 关联数组,默认情况下 Twig 不会打印该数组。 所以这个过滤器切割并提供一个常规数组供 Twig 使用。

    source.json

    {
        "user": {
            "family": {
                "table": [{
                    "First_Name": "John",
                    "Last_Name": "Foo",
                    "Age": 25,
                    "Role": "Brother"
                }, {
                    "First_Name": "Mary",
                    "Last_Name": "Bar",
                    "Age": 14,
                    "Role": "Sister"
                }, {
                    "First_Name": "Joe",
                    "Last_Name": "Baz",
                    "Age": 33,
                    "Role": "Uncle"
                }]
            }
        }
    }
    

    树枝

    <table>
      <thead>
        <tr> {# get table headers from the table row #}
          {% for row in user.family.table.0|cast_to_array %}
            <th>{{ row.0 | replace({'_': ' '}) }}</th>
          {% endfor %}
        </tr>
      </thead>
      <tbody>
        {% for row in user.family.table %}
          <tr>
          {% for key, value in row|cast_to_array %}
            <td>{{ value.1 }}</td>
          {% endfor %}
          </tr>
        {% endfor %}
      </tbody>
    </table>
    

    【讨论】:

    • 你有什么理由不这样做:$twig->addFilter(new Twig_SimpleFilter('cast_to_array', function ($stdClassObject) { return (array)$stdClassObject; }));
    • 对象可以像数组一样被迭代,Twig 应该提供功能,而不是把它拿走并强制进行不必要的数据按摩。
    【解决方案4】:

    我知道这是旧的,但不会

    $assoc_array = json_decode(json_encode($stdClassObject), TRUE);
    

    工作也一样?

    【讨论】:

      【解决方案5】:

      如果这对其他人有帮助。只要实现 PHP 的 Iterator 接口,就可以让 Twig 迭代对象的属性。

      在我的例子中,我有一个通用对象,它使用魔术方法 __get()、__set()、__isset() 和 __unset(),同时将键值对存储在私有数组中。这在 Twig 中可以正常工作,直到您想使用类似这样的方法迭代对象

      <ul>
      {% for prop, value in object %}
          <li>{{prop|replace({'_': ' '})|title}}</li>
      {% endfor %}
      </ul>
      

      为了让它工作,我必须实现 Iterator 接口。然后上面的代码就完美运行了。

      现在由于神奇的 __get() 属性名称也不区分大小写,所以这些都可以工作。

      <ul>
      {% for object in arrayOfObjects %}
          <li>{{ object.property }}</li>
          <li>{{ object.Property }}</li>
          <li>{{ object.PROPERTY }}</li>
      {% endfor %}
      </ul>
      

      【讨论】:

        【解决方案6】:
          {% for key, item in content.field_invoice_no if key|first != '#' %} <tr>
              <td>{{ item }}</td>
               <td> {{ content.field_invoice_date[key]  }}     </td>
               <td> {{ content.field_invoice_price[key]   }}       </td>
               </tr>
            {% endfor %}
        

        在键值上迭代对象

        【讨论】:

          【解决方案7】:

          我终于想出了一个香草 Twig 解决方案。我利用 reduce 过滤器将对象转换为数组。

          假设我们从后端获取了一个地址对象,并希望将其转换为关联数组,以便单独呈现每一行。

          {% set address = { firstName: 'Stack', lastName: 'Overflow', address: 'here', zipCode: '1234' } %}
          

          我们减少键并将它们添加到一个空数组中

          {% set addressLines = address|keys|reduce((carry, key) => carry|merge({ (key): attribute(address, key) }), []) %}
          

          这会导致:

          [ 'firstName' => 'Stack', 'lastName' => 'Overflow', 'address'=> 'here', 'zipCode' => '1234' ]
          

          现在我们可以在 for 循环中渲染它

          {% set allowedKeys = ['firstName', 'lastName', 'address'] %}
          {% for key, line in addressLines|filter((v, k) => k in allowedKeys) %}
              {{ line }}<br/>
          {% endfor %}
          

          【讨论】:

            猜你喜欢
            • 2012-01-08
            • 2016-05-12
            • 2021-08-28
            • 1970-01-01
            • 2014-08-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多