Я пытаюсь использовать переменную ветки для доступа к атрибутам другой переменной ветки, которая не работала, пока я не нашел функцию «атрибуты». Работает хорошо, за исключением случаев, когда мне нужно получить доступ к вложенным атрибутам. Это не работает, когда переменная, содержащая атрибут, на самом деле является объектом + атрибутом. Например:
{{ 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] - тут тоже не повезло.
Есть идеи?






Просто подумайте об именовании атрибутов: если один атрибут называется company.name, тогда вы можете получить к нему доступ таким образом. Если есть атрибут company, который сам содержит другой атрибут с именем name, вы не можете получить к нему доступ с помощью company.name.
Что вы могли бы попробовать вместо этого: напишите макрос ветки, который использует имя вашего поля, разбивает его на точку и рекурсивно вызывает себя, если оставшаяся часть все еще содержит точку.
Вы должны вкладывать свои вызовы в attribute.
Например. чтобы получить ту же функциональность, что и object1.object2.name, вы бы использовали:
{{ attribute(attribute(object1, 'object2'), 'name') }}
Чтобы расширить ответ Нико
Вы можете добиться этого с помощью следующего фрагмента:
главная.ветвь
{% 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 #}
Сначала разрешите
object2из вашего экземпляраobject1, затем разрешите свойство, которое вам нужно, в результате.