Cara membuat pohon di Twig

90

Saya ingin membuat pohon dengan kedalaman yang tidak dapat ditentukan (anak dari anak dari anak kecil, dll.). Saya perlu mengulang melalui array secara rekursif; bagaimana saya bisa melakukan ini di Twig?

T-RonX
sumber

Jawaban:

117

Saya bermain-main dengan ide domi27 dan muncul dengan ini. Saya membuat array bersarang sebagai pohon saya, ['link'] ['sublinks'] adalah null atau array lain yang lebih sama.

Template

File sub-template untuk digunakan kembali dengan:

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

Kemudian di template utama, panggil ini (semacam 'dengan' barang di sana):

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

Makro

Efek serupa dapat dicapai dengan makro:

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

Di template utama, lakukan ini:

{% import "macros/menu-macros.html" as macros %}
<ul class="main-menu">
    {{ macros.menu_links(links) }}
</ul>
random-coder-1920
sumber
9
Sangat baik terima kasih! Jika Anda ingin menggunakan makro di templat yang sama, Anda dapat menggunakan {{ _self.menu_links(links) }}.
flu
terima kasih, memikirkan hal ini membuat otak saya sakit tetapi jawaban Anda sangat masuk akal.
azzy81
Saya punya satu masalah dengan proyek saya dengan komentar. subkomentar (sublink) juga dimasukkan dalam koleksi utama (tautan). jadi sebelum memasukkan saya harus memeriksa apakah komentar memiliki entri 'orang tua'.
Jevgeni Smirnov
4
Menggunakan {{_self.menu_links}}adalah praktik yang buruk ! Baca catatan di sini: makro Saat Anda menentukan makro di templat tempat Anda akan menggunakannya, Anda mungkin tergoda untuk memanggil makro secara langsung melalui _self.input () daripada mengimpornya; meskipun tampaknya berhasil, ini hanyalah efek samping dari implementasi saat ini dan tidak akan berfungsi lagi di Twig 2.x. Anda harus mengimpor macroses secara lokal sekali lagi di insitemenu_links
dr.scre
37

Twig 2.0 - 2.11

Jika Anda ingin menggunakan makro di template yang sama , Anda harus menggunakan sesuatu seperti ini agar tetap kompatibel dengan 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>

Ini memperluas random-coderjawaban dan memasukkan dr.screpetunjuk ke dokumentasi Twig tentang makro yang sekarang digunakan _self, tetapi mengimpor secara lokal.

Ranting> = 2.11

Mulai Twig 2.11 , Anda dapat menghilangkan {% import _self as macros %}, karena makro sebaris diimpor secara otomatis di bawah _selfnamespace (lihat Pengumuman Twig: Impor makro otomatis ):

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

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

Jika Anda menjalankan PHP 5.4 atau lebih tinggi, ada solusi baru yang luar biasa (per Mei 2016) untuk masalah ini oleh Alain Tiemblo: https://github.com/ninsuo/jordan-tree .

Ini adalah tag "pohon" yang memiliki tujuan persis seperti ini. Markup akan terlihat seperti ini:

{% 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 %}
Jordan Lev
sumber
1
Anda tidak dapat meneruskan variabel tambahan ke subtree. Dalam kasus saya, kode perlu mengetahui apakah akan ada lebih banyak anak dan melewati jumlah level ke makro sehingga dapat melakukan a <div class="{{ classes[current_level].wrapper }} {% if levels > current_level %}accordion-wrapper{% endif %}">. Menghitung ini akan membutuhkan pengulangan level saat ini untuk kedua kalinya hanya untuk menangkap apakah ada anak.
chx
1

Pertama saya pikir ini dapat diselesaikan dengan cara yang mudah, tetapi tidak semudah itu.

Anda perlu membuat logika, mungkin dengan metode kelas PHP, kapan harus menyertakan subtemplate Twig dan kapan tidak.

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

Jadi Anda bisa menggunakan variabel loop Twig khusus , yang tersedia di dalam Twig for loop . Tapi saya tidak yakin tentang ruang lingkup variabel loop ini .

Ini dan informasi lainnya tersedia di Twigs "untuk" Docu !

domi27
sumber
1

Mengambil jawaban flu dan mengubahnya sedikit:

{# 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) }}
Sergey Atroshchenko
sumber
-1

Jawaban di sini menuntun saya ke solusi saya.

Saya memiliki entitas kategori dengan asosiasi banyak ke satu yang merujuk sendiri (induk ke anak).

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

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

Dalam template Twig saya, saya membuat tampilan pohon seperti ini:

<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>
Patric Robert Gutersohn
sumber
Bagaimana jika Anda memiliki lebih dari satu tingkat hierarki kategori?
Diragukan