Comment rendre un arbre dans Twig


89

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:


117

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>

9
Très bien merci! Si vous souhaitez utiliser la macro dans le même modèle, vous pouvez utiliser {{ _self.menu_links(links) }}.
grippe

merci, cette pensée m'a fait mal au cerveau, mais votre réponse est parfaitement logique.
azzy81

J'ai eu un problème avec mon projet avec des commentaires. des sous-commentaires (sous-liens) ont également été inclus dans la collection principale (liens). donc avant d'inclure j'ai dû vérifier si le commentaire avait une entrée «parent».
Jevgeni Smirnov

4
L'utilisation {{_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
dr.scre

35

Twig 2.0 - 2.11

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-coderla réponse et incorpore l dr.scre'astuce de la documentation Twig sur les macros à utiliser maintenant _self, mais à importer localement.

Brindille> = 2,11

Depuis Twig 2.11 , vous pouvez omettre le {% import _self as macros %}, car les macros intégrées sont importées automatiquement sous l' _selfespace 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>

2

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 %}

1
Vous ne pouvez pas transmettre de variables supplémentaires à 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.
chx

1

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 !


0

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) }}

-1

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>

Que faire si vous avez plus d'un niveau de hiérarchie de catégories?
pmoubed le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.