Je voudrais rendre un arbre avec une profondeur indéterminée (enfants d'enfants d'enfants, etc.). J'ai besoin de parcourir le tableau de manière récursive; comment puis-je faire cela dans Twig?
Réponses:
J'ai joué avec l'idée de domi27 et j'ai trouvé ça. J'ai créé un tableau imbriqué comme mon arbre, ['link'] ['sublinks'] est nul ou un autre tableau de plus de la même chose.
Modèles
Le fichier de sous-modèle avec lequel récurer:
<!--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 %}
Ensuite, dans le modèle principal, appelez ceci (sorte de trucs redondants 'avec'):
<ul class="main-menu">
{% include "includes/menu-links.html" with {'links':links} only %}
</ul>
Macros
Un effet similaire peut être obtenu avec des 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 %}
Dans le modèle principal, procédez comme suit:
{% import "macros/menu-macros.html" as macros %}
<ul class="main-menu">
{{ macros.menu_links(links) }}
</ul>
{{_self.menu_links}}
est une mauvaise pratique ! Lisez une note ici: macro Lorsque vous définissez une macro dans le modèle où vous allez l'utiliser, vous pourriez être tenté d'appeler la macro directement via _self.input () au lieu de l'importer; même si cela semble fonctionner, ce n'est qu'un effet secondaire de l'implémentation actuelle et cela ne fonctionnera plus dans Twig 2.x. Vous devez à nouveau importer des macros localement sur placemenu_links
Si vous souhaitez utiliser une macro dans le même modèle , vous devez utiliser quelque chose comme ceci pour rester compatible avec 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>
Ceci étend random-coder
la réponse et incorpore l dr.scre
'astuce de la documentation Twig sur les macros à utiliser maintenant _self
, mais à importer localement.
Depuis Twig 2.11 , vous pouvez omettre le {% import _self as macros %}
, car les macros intégrées sont importées automatiquement sous l' _self
espace de noms (voir Annonce Twig: importation automatique de macro ):
{# {% import _self as macros %} - Can be removed #}
<ul class="main-menu">
{{ _self.menu_links(links) }} {# Use _self for inlined macros #}
</ul>
Si vous utilisez PHP 5.4 ou supérieur, il existe une merveilleuse nouvelle solution (à partir de mai 2016) à ce problème par Alain Tiemblo: https://github.com/ninsuo/jordan-tree .
C'est une balise "arbre" qui sert exactement cet objectif. Le balisage ressemblerait à ceci:
{% 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
. Dans mon cas, le code a besoin de savoir s'il y aura plus d'enfants et il passe le nombre de niveaux à la macro afin qu'elle puisse faire un <div class="{{ classes[current_level].wrapper }} {% if levels > current_level %}accordion-wrapper{% endif %}">
. Pour calculer cela, il faudrait répéter le niveau actuel une seconde fois pour déterminer s'il y a des enfants.
J'ai d'abord pensé que cela pouvait être résolu de manière simple, mais ce n'est pas si simple.
Vous devez créer une logique, peut-être avec une méthode de classe PHP, quand inclure un sous-modèle Twig et quand non.
<!-- 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>
Vous pouvez donc utiliser la variable de boucle Twig spéciale , qui est disponible dans une boucle Twig for . Mais je ne suis pas sûr de la portée de cette boucle variable de .
Ceci et d'autres informations sont disponibles sur Twigs "pour" Docu !
A pris la réponse de la grippe et l'a modifiée un peu:
{# 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) }}
Les réponses ici mènent à ma solution.
J'ai une entité de catégorie avec une association plusieurs-à-un auto-référencée (parent-enfant).
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
*/
private $parent;
/**
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
*/
private $children;
Dans mon modèle Twig, je rend l'arborescence comme ceci:
<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) }}
.