简体   繁体   English

如何使用 Twig 的属性函数访问嵌套对象属性

[英]How to use Twig's attributed function to access nested object properties

I'm trying to use a twig variable to access attributes of another twig variable which was not working until I found the "attributes" function.我正在尝试使用 twig 变量来访问另一个 twig 变量的属性,该变量在我找到“属性”函数之前不起作用。 Works well except in the cases where I need to access nested attributes.除了需要访问嵌套属性的情况外,效果很好。 It doesn't work when the variable containing the attribute is actually an object + attribute.当包含属性的变量实际上是对象 + 属性时,它不起作用。 For example:例如:

{{ attribute(object1, variable) }} where variable = name, works just fine. {{ attribute(object1, variable) }}其中变量 = 名称,效果很好。 {{ attribute(object1, variable) }} where variable = object2.name, doesn't work. {{ attribute(object1, variable) }}其中 variable = object2.name,不起作用。 However, a hard coded test of {{ object1.object2.name }} does work.但是, {{ object1.object2.name }}的硬编码测试确实有效。

Here's how I got to this point...I have a yaml config file that gets parsed by the controller and passes it to twig in an array named 'config'.这是我如何做到这一点......我有一个 yaml 配置文件,它由控制器解析并将其传递给名为“config”的数组中的 twig。 It contains parameters to define what gets displayed by the twig template.它包含定义树枝模板显示内容的参数。

fields:
  - name: company.name
    label: 'ODM'
    indexView: true
    recodrdView: true
  - name: location
    label: 'Location'
    indexView: true
    recordView: true

Additionally, an array of objects (entities) gets passed to the template for rendering.此外,一组对象(实体)被传递到模板进行渲染。

The above "fields.name" is the name of the entity property.上面的“fields.name”是实体属性的名称。 I iterate over the array of entities and then iterate over the config.fields array to determine what to display.我遍历实体数组,然后遍历 config.fields 数组以确定要显示的内容。 Here's the twig code:这是树枝代码:

{% for data in datum %}
    <tr>
    {% for field in config.fields %}
        {% if field.indexView %}
            <td>{{ attribute(data, field.name }}</td>       
        {% endif %}
    {% endfor %}
    </tr>
{% endfor %}

I get the error:我收到错误:

Neither the property "company.name" nor one of the methods "company.name()", "getcompany.name()"/"iscompany.name()"/"hascompany.name()" or "__call()" exist and have public access in class "App\Entity\Odm".

I suppose I could split up the field.name string with a '.'我想我可以用 '.' 拆分 field.name 字符串。 delimiter and then make the necessary number of calls to attribute, but I'm really hoping there's a more eloquent solution.分隔符,然后对属性进行必要数量的调用,但我真的希望有一个更有说服力的解决方案。 I've also tried _context['data.'我也试过 _context['data.' ~ field.name] - no luck there either. ~ field.name] - 也没有运气。

Any ideas?有任何想法吗?

Just think about the naming of the attributes: is a single attribute called company.name , then you can access it this way.想想属性的命名:是一个名为company.name的单个属性,那么你可以通过这种方式访问​​它。 If there is an attribute company which itself holds another attribute called name , then you cannot access it using company.name .如果有一个属性company本身拥有另一个名为name属性,那么您不能使用company.name访问它。

What you could try instead: write a twig macro that uses your field name, splits it a the dot and recursively calls itself if the remaining part still contains a dot.您可以尝试:编写一个使用您的字段名称的树枝宏,将其拆分为一个点,如果剩余部分仍然包含一个点,则递归调用自身。

You should nest your calls to attribute .您应该嵌套对attribute的调用。

Eg to get the same functionality as object1.object2.name you would use:例如,要获得与object1.object2.name相同的功能,您将使用:

{{ attribute(attribute(object1, 'object2'), 'name') }}

To expand on Nico 's answer扩展Nico的回答

You could achieve this with the following snippet:您可以使用以下代码段实现此目的:

main.twig主枝

{% import 'macro.twig' as macro %}
{{ macro.get_attribute(foo, 'bar.foobar') }}

macro.twig大树枝

{% macro get_attribute(object, attributes) %}
    {% apply spaceless %}
    {% set attributes = attributes|split('.') %}

    {% set value = object %}
    {% for attribute in attributes %}
        {% set value = attribute(value, attribute|trim) is defined ? attribute(value, attribute|trim) : null %}
    {% endfor %}
    {{ value }}
    {% endapply %}    
{% endmacro %}

demo演示


However a side note, if you are trying to use a macro for this and store the "output" in a variable, keep in mind that a macro will return an instance of Twig_Markup .但是,附带说明一下,如果您尝试为此使用宏并将“输出”存储在变量中,请记住,宏将返回Twig_Markup的实例。 This means you can't use the value later on.这意味着您以后不能使用该值。

An example:一个例子:

data数据

foo:
    bar:
        foobar: 'Lorem Lipsum'

main.twig主枝

{% set bar = macro.get_attribute(foo, 'bar') %}
{{ bar.foobar }} {# <--- error cause `foobar` is not a member of `Twig_Markup` #}

The real value of bar actually is not even an object or array, but just a string with, in this example, Array as content bar的真正值实际上甚至不是一个对象或数组,而只是一个字符串,在这个例子中, Array作为内容

{% set bar = macro.get_attribute(foo, 'bar') %}
{{ bar }} {# output: Array #}

如果您使用的是 Twig >= 2.10,则可以使用reduce()过滤器:

{{ field.name|split('.')|reduce((carry, v) => carry ? attribute(carry, v) : null, data) }}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM