Як зробити дерево в Twig


89

Я хотів би зробити дерево з невизначеною глибиною (діти дітей, дітей тощо). Мені потрібно прокрутити масив рекурсивно; як я можу це зробити в Twig?

Відповіді:


117

Я погрався з ідеєю domi27 і придумав це. Я створив вкладений масив як моє дерево, ['link'] ['sublinks'] має значення null або інший масив із того самого.

Шаблони

Файл під шаблону для повторного використання:

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

Потім у головному шаблоні викличте це (вид зайвого "з" там речами):

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

Макроси

Подібного ефекту можна досягти за допомогою макросів:

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

У головному шаблоні зробіть так:

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

9
Дуже добре, дякую! Якщо ви хочете використовувати макрос у тому самому шаблоні, який ви можете використовувати {{ _self.menu_links(links) }}.
грип

дякую, від думки про це мені боліло мозок, але ваша відповідь має цілком сенс.
azzy81

У мене було одне питання з моїм проектом із коментарями. підкоментарі (підсилки) також були включені до основної колекції (посилання). тому перед включенням мені довелося перевірити, чи є в коментарі «батьківський» запис.
Jevgeni Smirnov

4
Використання {{_self.menu_links}}- погана практика ! Прочитайте примітку тут: макрос Коли ви визначаєте макрос у шаблоні, де ви збираєтесь його використовувати, у вас може виникнути спокуса викликати макрос безпосередньо через _self.input () замість того, щоб імпортувати його; навіть якщо це, здається, працює, це лише побічний ефект поточної реалізації, і це вже не буде працювати в Twig 2.x. Вам слід імпортувати макроси локально ще раз, menu_links
незважаючи на це

35

Гілочка 2.0 - 2.11

Якщо ви хочете використовувати макрос у тому самому шаблоні , вам слід використовувати щось подібне, щоб залишатися сумісним із 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>

Це розширює random-coderвідповідь і включає dr.screпідказку до документації Twig про макроси, які зараз можна використовувати_self , але імпортувати локально.

Гілочка> = 2.11

Починаючи з Twig 2.11 , ви можете пропустити {% import _self as macros %}, оскільки вбудовані макроси імпортуються автоматично під _selfпростір імен (див. Оголошення Twig: Автоматичний імпорт макросів ):

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

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

2

Якщо ви використовуєте PHP 5.4 або новішої версії, є чудове нове рішення (станом на травень 2016 року) цієї проблеми Алена Тіембло: https://github.com/ninsuo/jordan-tree .

Це тег "дерево", який служить саме цій меті. Розмітка буде виглядати так:

{% 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
Ви не можете передати додаткові змінні subtree. У моєму випадку код повинен знати, чи буде більше дітей, і він передає кількість рівнів макросу, щоб він міг зробити a <div class="{{ classes[current_level].wrapper }} {% if levels > current_level %}accordion-wrapper{% endif %}">. Для обчислення цього потрібно буде повторно повторити поточний рівень лише для того, щоб визначити, чи є діти.
chx

1

Спочатку я думав, що це можна вирішити прямолінійно, але це не так просто.

Вам потрібно створити логіку, можливо, за допомогою методу класу PHP, коли включати підшаблон Twig, а коли ні.

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

Таким чином, ви можете використовувати спеціальну змінну циклу Twig , яка доступна всередині циклу Twig for . Але я не впевнений в області дії цієї змінної циклу .

Ця та інша інформація доступна на Twigs "для" Docu !


0

Взяв відповідь на грип і трохи її змінив:

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

Відповіді тут ведуть до мого рішення.

У мене є сутність категорії із самореференційною асоціацією багато-до-одного (від батьків до дітей).

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

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

У моєму шаблоні Twig я відображаю вид дерева таким чином:

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

Що робити, якщо у вас є більше ніж один рівень ієрархії категорій?
pmoubed
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.