Làm thế nào để kết xuất một cái cây trong Twig


89

Tôi muốn kết xuất một cái cây với độ sâu không xác định (trẻ em của trẻ em, v.v.). Tôi cần lặp qua mảng một cách đệ quy; làm thế nào tôi có thể làm điều này trong Twig?

Câu trả lời:


117

Tôi đã thử với ý tưởng của domi27nghĩ ra điều này. Tôi đã tạo một mảng lồng nhau dưới dạng cây của tôi, ['link'] ['sublinks'] là null hoặc một mảng khác giống nhau hơn.

Mẫu

Tệp mẫu phụ để đệ quy:

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

Sau đó, trong mẫu chính, hãy gọi điều này (loại thừa 'với' thứ ở đó):

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

Macro

Hiệu ứng tương tự có thể đạt được với 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 %}

Trong mẫu chính, hãy làm như sau:

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

9
Rất tốt cảm ơn bạn! Nếu bạn muốn sử dụng macro trong cùng một mẫu, bạn có thể sử dụng {{ _self.menu_links(links) }}.
cúm

cảm ơn bạn, ý nghĩ về điều này làm tôi đau đầu nhưng câu trả lời của bạn rất hợp lý.
azzy81

Tôi có một vấn đề với dự án của mình với các nhận xét. tiểu phần (liên kết con) cũng được đưa vào bộ sưu tập chính (liên kết). vì vậy trước khi đưa vào, tôi phải kiểm tra xem nhận xét có mục 'cha' hay không.
Jevgeni Smirnov

4
Sử dụng {{_self.menu_links}}là một thực hành xấu ! Đọc ghi chú ở đây: macro Khi bạn xác định một macro trong mẫu mà bạn sẽ sử dụng nó, bạn có thể muốn gọi macro trực tiếp qua _self.input () thay vì nhập nó; ngay cả khi có vẻ hoạt động, đây chỉ là một tác dụng phụ của việc triển khai hiện tại và nó sẽ không hoạt động nữa trong Twig 2.x. Bạn nên nhập macro cục bộ một lần nữa trong trangmenu_links
dr.scre

35

Cành 2.0 - 2.11

Nếu bạn muốn sử dụng macro trong cùng một mẫu , bạn nên sử dụng một cái gì đó như thế này để duy trì tương thích với 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>

Điều này mở rộng random-codercâu trả lời của và kết hợp dr.scregợi ý với tài liệu Twig về macro để sử dụng bây giờ _self, nhưng nhập cục bộ.

Cành> = 2,11

Kể từ Twig 2.11 , bạn có thể bỏ qua {% import _self as macros %}, vì macro nội tuyến được nhập tự động trong _selfkhông gian tên (xem thông báo Twig: Nhập macro tự động ):

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

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

2

Nếu bạn đang chạy PHP 5.4 trở lên, có một giải pháp mới tuyệt vời (kể từ tháng 5 năm 2016) cho vấn đề này của Alain Tiemblo: https://github.com/ninsuo/jordan-tree .

Đó là một thẻ "cây" phục vụ mục đích chính xác này. Đánh dấu sẽ giống như sau:

{% 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
Bạn không thể chuyển các biến bổ sung vào subtree. Trong trường hợp của tôi, mã cần biết liệu sẽ có nhiều con hơn hay không và nó chuyển số cấp đến macro để nó có thể thực hiện a <div class="{{ classes[current_level].wrapper }} {% if levels > current_level %}accordion-wrapper{% endif %}">. Việc tính toán điều này sẽ yêu cầu lặp lại mức hiện tại lần thứ hai chỉ để nắm bắt xem có bất kỳ con nào hay không.
chx

1

Đầu tiên, tôi nghĩ điều này có thể được giải quyết một cách dễ dàng, nhưng nó không dễ dàng như vậy.

Bạn cần tạo logic, có thể với một phương thức lớp PHP, khi nào thì đưa vào phương thức con Twig và khi nào thì không.

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

Vì vậy, bạn có thể sử dụng biến vòng lặp Twig đặc biệt , có sẵn bên trong vòng lặp Twig for . Nhưng tôi không chắc về phạm vi của biến vòng lặp này .

Thông tin này và các thông tin khác có trên Twigs "for" Docu !


0

Nhận câu trả lời của bệnh cúm và sửa đổi nó một chút:

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

Các câu trả lời ở đây dẫn tôi đến giải pháp của tôi.

Tôi có một thực thể danh mục với liên kết nhiều-một tự tham chiếu (cha mẹ với con cái).

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

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

Trong mẫu Twig của tôi, tôi đang hiển thị chế độ xem dạng cây như sau:

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

Điều gì sẽ xảy ra nếu bạn có nhiều hơn một mức phân cấp danh mục?
pmoubed
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.