Eu gostaria de representar uma árvore com uma profundidade indeterminada (filhos de filhos de crianças, etc.). Eu preciso percorrer a matriz recursivamente; como posso fazer isso no Twig?
Respostas:
Eu brinquei com a ideia da domi27 e cheguei a essa conclusão . Fiz uma matriz aninhada como minha árvore, ['link'] ['sublinks'] é nula ou outra matriz de mais do mesmo.
Modelos
O arquivo de submodelo para recursar com:
<!--includes/menu-links.html-->
{% for link in links %}
<li>
<a href="{{ link.href }}">{{ link.name }}</a>
{% if link.sublinks %}
<ul>
{% include "includes/menu-links.html" with {'links': link.sublinks} %}
</ul>
{% endif %}
</li>
{% endfor %}
Então, no modelo principal, chame isso (tipo de coisa redundante 'com' lá):
<ul class="main-menu">
{% include "includes/menu-links.html" with {'links':links} only %}
</ul>
Macros
Um efeito semelhante pode ser alcançado com macros:
<!--macros/menu-macros.html-->
{% macro menu_links(links) %}
{% for link in links %}
<li>
<a href="{{ link.href }}">{{ link.name }}</a>
{% if link.sublinks %}
<ul>
{{ _self.menu_links(link.sublinks) }}
</ul>
{% endif %}
</li>
{% endfor %}
{% endmacro %}
No modelo principal, faça o seguinte:
{% import "macros/menu-macros.html" as macros %}
<ul class="main-menu">
{{ macros.menu_links(links) }}
</ul>
{{_self.menu_links}}
é uma prática ruim ! Leia uma observação aqui: macro Quando você define uma macro no modelo em que vai usá-la, pode ficar tentado a chamar a macro diretamente via _self.input () em vez de importá-la; mesmo que pareça funcionar, este é apenas um efeito colateral da implementação atual e não funcionará mais no Twig 2.x. Você deve importar macroses localmente mais uma vez no sitemenu_links
Se você quiser usar uma macro no mesmo modelo , deve usar algo assim para permanecer compatível com o Twig 2.x :
{% macro menu_links(links) %}
{% import _self as macros %}
{% for link in links %}
<li>
<a href="{{ link.href }}">{{ link.name }}</a>
{% if link.sublinks %}
<ul>
{{ macros.menu_links(link.sublinks) }}
</ul>
{% endif %}
</li>
{% endfor %}
{% endmacro %}
{% import _self as macros %}
<ul class="main-menu">
{{ macros.menu_links(links) }}
</ul>
Isso estende random-coder
a resposta de e incorpora dr.scre
a dica de à documentação do Twig sobre macros a serem usadas agora _self
, mas importadas localmente.
A partir do Twig 2.11 , você pode omitir o {% import _self as macros %}
, já que as macros embutidas são importadas automaticamente no _self
namespace (consulte o anúncio do Twig: Importação automática de macro ):
{# {% import _self as macros %} - Can be removed #}
<ul class="main-menu">
{{ _self.menu_links(links) }} {# Use _self for inlined macros #}
</ul>
Se você estiver executando o PHP 5.4 ou superior, há uma nova solução maravilhosa (em maio de 2016) para este problema por Alain Tiemblo: https://github.com/ninsuo/jordan-tree .
É uma tag "árvore" que serve exatamente a esse propósito. A marcação ficaria assim:
{% tree link in links %}
{% if treeloop.first %}<ul>{% endif %}
<li>
<a href="{{ link.href }}">{{ link.name }}</a>
{% subtree link.sublinks %}
</li>
{% if treeloop.last %}</ul>{% endif %}
{% endtree %}
subtree
. No meu caso, o código precisa saber se haverá mais filhos e passa o número de níveis para a macro para que possa fazer um <div class="{{ classes[current_level].wrapper }} {% if levels > current_level %}accordion-wrapper{% endif %}">
. Calcular isso exigiria a iteração do nível atual uma segunda vez apenas para capturar se há algum filho.
Primeiro pensei que isso poderia ser resolvido de uma maneira simples, mas não é tão fácil.
Você precisa criar lógica, talvez com um método de classe PHP, quando incluir um subtemplate Twig e quando não.
<!-- tpl.html.twig -->
<ul>
{% for key, item in menu %}
{# Pseudo Twig code #}
{% if item|hassubitem %}
{% include "subitem.html.tpl" %}
{% else %}
<li>{{ item }}</li>
{% endif %}
{% endfor %}
</ul>
Portanto, você poderia usar a variável de loop Twig especial , que está disponível dentro de um loop for Twig . Mas não tenho certeza sobre o escopo dessa variável de loop .
Esta e outras informações estão disponíveis no Twigs "for" Docu !
Pegou a resposta da gripe e modificou um pouco:
{# Macro #}
{% macro tree(items) %}
{% import _self as m %}
{% if items %}
<ul>
{% for i in items %}
<li>
<a href="{{ i.url }}">{{ i.title }}</a>
{{ m.tree(i.items) }}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{# Usage #}
{% import 'macros.twig' as m %}
{{ m.tree(items) }}
As respostas aqui me levam à minha solução.
Eu tenho uma entidade de categoria com uma associação muitos-para-um com autorreferência (pai para filhos).
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
*/
private $parent;
/**
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
*/
private $children;
No meu modelo Twig, estou renderizando a visualização em árvore assim:
<ul>
{% for category in categories %}
{% if category.parent == null %}
<li>
<a href="{{ category.id }}">{{ category.name }}</a>
{% if category.children|length > 0 %}
<ul>
{% for category in category.children %}
<li>
<a href="{{ category.id }}">{{ category.name }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{{ _self.menu_links(links) }}
.