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:
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>
{{_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
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-coder
la risposta di e incorpora dr.scre
il suggerimento di Twig alla documentazione sulle macro da utilizzare ora _self
, ma importate localmente.
A partire da Twig 2.11 , è possibile omettere {% import _self as macros %}
, poiché le macro inline vengono importate automaticamente nello _self
spazio 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>
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 %}
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.
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 !
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) }}
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>
{{ _self.menu_links(links) }}
.