web-dev-qa-db-fra.com

Comment rendre un arbre dans Twig

Je voudrais rendre un arbre avec une profondeur indéterminée (enfants d'enfants enfants d'enfants, etc.). J'ai besoin de parcourir le tableau de manière récursive; Comment puis-je faire cela dans Twig?

86
T-RonX

Merci domi27, je me suis amusé avec votre idée et je l’ai suggérée. J'ai créé un tableau imbriqué sous forme d'arborescence, ['link'] ['sublinks'] est nul ou un autre tableau contenant plusieurs éléments identiques.

Modèles

Le fichier de sous-modèle à recurse avec:

<!--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 (un peu redondant 'avec' ici):

<ul class="main-menu">
    {% include "includes/menu-links.html" with {'links':links} only %}
</ul>

Macros

Un effet similaire peut être obtenu avec les 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>

J'espère que ça aide :)

104
random-coder-1920

Si vous voulez 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 la réponse de random-coder et intègre le conseil de dr.scre à la documentation de twig sur les macros pour utiliser maintenant _self mais importer localement.

29
flu

J'ai d'abord pensé que cela pourrait être résolu directement, mais ce n'est pas si facile.

Vous devez créer une logique, peut-être avec une méthode de classe php, quand inclure un sous-modèle de brindille ou 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 spéciale twig loop , disponible dans une boucle twig for loop. Mais je ne suis pas sûr de la portée de cette variable loop.

Désolé de ne fournir qu’une approche et non une solution, mais j’espère peut-être que mes pensées pourront vous aider (un peu).

Ceci et d'autres informations sont disponibles sur Twigs "for" Docu !

2
domi27

Si vous utilisez PHP 5.4 ou une version ultérieure, il existe une nouvelle solution merveilleuse (à partir de mai 2016) par Alain Tiemblo: https://github.com/ninsuo/jordan-tree

C'est une balise "tree" 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 %}
2
Jordan Lev

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

Les réponses ici mènent à ma solution.

J'ai une entité de catégorie avec l'association auto-référencée ManyToOne (parent à enfants).

/**
 * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
 */
private $parent;

/**
 * @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
 */
private $children;

Dans mon modèle de brindille, je reproduis la vue arborescente 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>