Как использовать атрибутивную функцию Twig для доступа к свойствам вложенных объектов

Я пытаюсь использовать переменную ветки для доступа к атрибутам другой переменной ветки, которая не работала, пока я не нашел функцию «атрибуты». Работает хорошо, за исключением случаев, когда мне нужно получить доступ к вложенным атрибутам. Это не работает, когда переменная, содержащая атрибут, на самом деле является объектом + атрибутом. Например:

{{ attribute(object1, variable) }} где переменная = имя, отлично работает. {{ attribute(object1, variable) }} где переменная = object2.name, не работает. Однако жестко закодированный тест {{ object1.object2.name }} работает.

Вот как я дошел до этого... У меня есть конфигурационный файл yaml, который анализируется контроллером и передается в twig в массиве с именем 'config'. Он содержит параметры для определения того, что будет отображаться шаблоном ветки.

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

Кроме того, в шаблон для рендеринга передается массив объектов (сущностей).

Приведенное выше «fields.name» — это имя свойства сущности. Я перебираю массив сущностей, а затем перебираю массив config.fields, чтобы определить, что отображать. Вот код ветки:

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

Я получаю сообщение об ошибке:

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".

Я полагаю, я мог бы разделить строку field.name с помощью '.' разделитель, а затем сделать необходимое количество вызовов атрибута, но я очень надеюсь, что есть более красноречивое решение. Я также пробовал _context['data.' ~ field.name] - тут тоже не повезло.

Есть идеи?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
0
2 491
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Просто подумайте об именовании атрибутов: если один атрибут называется company.name, тогда вы можете получить к нему доступ таким образом. Если есть атрибут company, который сам содержит другой атрибут с именем name, вы не можете получить к нему доступ с помощью company.name.

Что вы могли бы попробовать вместо этого: напишите макрос ветки, который использует имя вашего поля, разбивает его на точку и рекурсивно вызывает себя, если оставшаяся часть все еще содержит точку.

Вы должны вкладывать свои вызовы в attribute.

Например. чтобы получить ту же функциональность, что и object1.object2.name, вы бы использовали:

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

Сначала разрешите object2 из вашего экземпляра object1, затем разрешите свойство, которое вам нужно, в результате.

emarref 15.05.2019 22:39
Ответ принят как подходящий

Чтобы расширить ответ Нико

Вы можете добиться этого с помощью следующего фрагмента:

главная.ветвь

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

макрос.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 %}

демо


Однако примечание: если вы пытаетесь использовать для этого макрос и сохранить «выход» в переменной, имейте в виду, что макрос вернет экземпляр Twig_Markup. Это означает, что вы не сможете использовать это значение позже.

Пример:

данные

foo:
    bar:
        foobar: 'Lorem Lipsum'

главная.ветвь

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

Реальное значение 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) }}

Другие вопросы по теме