Come rendere un albero in Twig


89

Vorrei rendere un albero con una profondità indeterminata (figli di figli di bambini, ecc.). Ho bisogno di scorrere l'array in modo ricorsivo; come posso farlo in Twig?

Risposte:


117

Ho giocato con l'idea di domi27 e ho avuto questo. Ho creato un array nidificato come il mio albero, ['link'] ['sublinks'] è nullo o un altro array di più dello stesso.

Modelli

Il file di sotto-modello con cui ricorrere:

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

Quindi nel modello principale, chiama questo (tipo di cose ridondanti "con" lì):

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

Macro

Un effetto simile può essere ottenuto con le macro:

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

Nel modello principale, fai questo:

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

9
Molto bene grazie! Se vuoi usare la macro nello stesso modello puoi usare {{ _self.menu_links(links) }}.
influenza il

grazie, il pensiero di questo mi ha fatto male al cervello ma la tua risposta ha perfettamente senso.
azzy81

Ho avuto un problema con il mio progetto con i commenti. anche i sottocommenti (collegamenti secondari) sono stati inclusi nella raccolta principale (collegamenti). quindi prima di includerlo ho dovuto controllare se il commento aveva una voce "genitore".
Jevgeni Smirnov

4
L'utilizzo {{_self.menu_links}}è una cattiva pratica ! Leggi una nota qui: macro Quando definisci una macro nel modello in cui la utilizzerai, potresti essere tentato di chiamare la macro direttamente tramite _self.input () invece di importarla; anche se sembra funzionare, questo è solo un effetto collaterale dell'attuale implementazione e non funzionerà più in Twig 2.x. Dovresti importare le macro localmente ancora una volta insitemenu_links
dr.scre

35

Twig 2.0 - 2.11

Se vuoi usare una macro nello stesso modello , dovresti usare qualcosa di simile per rimanere compatibile con 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>

Questo estende random-coderla risposta di e incorpora dr.screil suggerimento di Twig alla documentazione sulle macro da utilizzare ora _self, ma importate localmente.

Ramoscello> = 2.11

A partire da Twig 2.11 , è possibile omettere {% import _self as macros %}, poiché le macro inline vengono importate automaticamente nello _selfspazio dei nomi (vedere l' annuncio di Twig: importazione automatica delle macro ):

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

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

2

Se utilizzi PHP 5.4 o versioni successive, c'è una nuova meravigliosa soluzione (a partire da maggio 2016) a questo problema di Alain Tiemblo: https://github.com/ninsuo/jordan-tree .

È un tag "albero" che serve esattamente a questo scopo. Il markup sarebbe simile a questo:

{% 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
Non puoi passare variabili aggiuntive a subtree. Nel mio caso, il codice deve sapere se ci saranno più figli e passa il numero di livelli alla macro in modo che possa eseguire un file <div class="{{ classes[current_level].wrapper }} {% if levels > current_level %}accordion-wrapper{% endif %}">. Calcolarlo richiederebbe l'iterazione del livello corrente una seconda volta solo per rilevare se ci sono figli.
chx

1

Per prima cosa ho pensato che potesse essere risolto in modo semplice, ma non è così facile.

È necessario creare logica, magari con un metodo di classe PHP, quando includere un subtemplate Twig e quando no.

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

Quindi potresti usare la speciale variabile di loop Twig , che è disponibile all'interno di un Twig for loop . Ma non sono sicuro dell'ambito di questa variabile di ciclo .

Questa ed altre informazioni sono disponibili sul Ramoscelli "per" Docu !


0

Ha preso la risposta dell'influenza e l'ha modificata un po ':

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

Le risposte qui mi portano alla mia soluzione.

Ho un'entità categoria con un'associazione molti-a-uno autoreferenziale (da padre a figlio).

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

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

Nel mio modello Twig sto rendendo la visualizzazione ad albero in questo modo:

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

Cosa succede se hai più di un livello di gerarchia di categorie?
pmoubed
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.