So rendern Sie einen Baum in Twig


89

Ich möchte einen Baum mit einer unbestimmten Tiefe rendern (Kinder von Kindern von Kindern usw.). Ich muss das Array rekursiv durchlaufen. Wie kann ich das in Twig machen?

Antworten:


117

Ich habe mit der Idee von domi27 herumgespielt und mir diese ausgedacht . Ich habe ein verschachteltes Array erstellt, da mein Baum, ['link'] ['sublinks'] null oder ein anderes Array von mehreren derselben ist.

Vorlagen

Die Subvorlagendatei, mit der rekursiv gearbeitet werden soll:

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

Rufen Sie dann in der Hauptvorlage Folgendes auf (Art redundantes 'mit' Zeug dort):

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

Makros

Ein ähnlicher Effekt kann mit Makros erzielt werden:

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

Gehen Sie in der Hauptvorlage folgendermaßen vor:

{% import "macros/menu-macros.html" as macros %}
<ul class="main-menu">
    {{ macros.menu_links(links) }}
</ul>

9
Sehr gut danke Ihnen! Wenn Sie das Makro in derselben Vorlage verwenden möchten, können Sie es verwenden {{ _self.menu_links(links) }}.
Grippe

Danke, der Gedanke daran hat mein Gehirn verletzt, aber deine Antwort macht vollkommen Sinn.
Azzy81

Ich hatte ein Problem mit meinem Projekt mit Kommentaren. Unterkommentare (Unterlinks) wurden ebenfalls in die Hauptsammlung (Links) aufgenommen. Vor dem Einschließen musste ich überprüfen, ob der Kommentar einen 'Eltern'-Eintrag hatte.
Jevgeni Smirnov

4
Verwenden {{_self.menu_links}}ist eine schlechte Praxis ! Lesen Sie hier einen Hinweis: Makro Wenn Sie ein Makro in der Vorlage definieren, in der Sie es verwenden möchten, könnten Sie versucht sein, das Makro direkt über _self.input () aufzurufen, anstatt es zu importieren. Selbst wenn es zu funktionieren scheint, ist dies nur ein Nebeneffekt der aktuellen Implementierung und wird in Twig 2.x nicht mehr funktionieren. Sie sollten Makros noch einmal lokal menu_links
insite

35

Zweig 2.0 - 2.11

Wenn Sie ein Makro in derselben Vorlage verwenden möchten , sollten Sie Folgendes verwenden, um mit Twig 2.x kompatibel zu bleiben :

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

Dies erweitert random-coderdie Antwort und enthält dr.screden Hinweis auf die Twig-Dokumentation zu Makros , die jetzt verwendet _self, aber lokal importiert werden sollen.

Zweig> = 2,11

Ab Twig 2.11 können Sie das weglassen {% import _self as macros %}, da Inline-Makros automatisch unter dem _selfNamespace importiert werden (siehe Twig-Ankündigung: Automatischer Makroimport ):

{# {% import _self as macros %} - Can be removed #}

<ul class="main-menu">
    {{ _self.menu_links(links) }} {# Use _self for inlined macros #}
</ul>

2

Wenn Sie PHP 5.4 oder höher verwenden, gibt es eine wunderbare neue Lösung (Stand Mai 2016) für dieses Problem von Alain Tiemblo: https://github.com/ninsuo/jordan-tree .

Es ist ein "Baum" -Tag, das genau diesem Zweck dient. Markup würde so aussehen:

{% 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
Sie können keine zusätzlichen Variablen an übergeben subtree. In meinem Fall muss der Code wissen, ob es mehr untergeordnete Elemente geben wird, und er übergibt die Anzahl der Ebenen an das Makro, damit es a ausführen kann <div class="{{ classes[current_level].wrapper }} {% if levels > current_level %}accordion-wrapper{% endif %}">. Um dies zu berechnen, müsste die aktuelle Ebene ein zweites Mal wiederholt werden, um zu erfassen, ob Kinder vorhanden sind.
chx

1

Zuerst dachte ich, dass dies auf einfache Weise gelöst werden kann, aber es ist nicht so einfach.

Sie müssen Logik erstellen, möglicherweise mit einer PHP-Klassenmethode, wann eine Twig-Untervorlage eingefügt werden soll und wann nicht.

<!-- 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>

Sie können also die spezielle Twig-Schleifenvariable verwenden , die in einer Twig for-Schleife verfügbar ist . Über den Umfang dieser Schleifenvariablen bin ich mir jedoch nicht sicher .

Diese und andere Informationen sind auf Twigs "für" Docu !


0

Nahm die Antwort der Grippe und änderte sie ein wenig:

{# 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

Die Antworten hier führen mich zu meiner Lösung.

Ich habe eine Kategorieentität mit einer selbstreferenzierenden Viele-zu-Eins-Zuordnung (Eltern zu Kindern).

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

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

In meiner Twig-Vorlage rendere ich die Baumansicht folgendermaßen:

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

Was ist, wenn Sie mehr als eine Ebene der Kategoriehierarchie haben?
pmoubed
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.