web-dev-qa-db-ja.com

Twigでツリーをレンダリングする方法

未決定の深さ(子供の子供の子供など)でツリーをレンダリングしたいと思います。配列を再帰的にループする必要があります。 Twigでこれを行うにはどうすればよいですか?

89
T-RonX

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

次に、メインテンプレートでこれを呼び出します(そこにある種の冗長な「with」のもの):

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

それが役に立てば幸い :)

107

同じテンプレートでMacroを使用したい場合、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のヒントを マクロに関するドキュメンテーション に組み込んで、現在_selfを使用し、ローカルにインポートします。


編集(2019-07-01):

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

PHP 5.4以降)を実行している場合、Alain Tiembloによるこの問題に対する素晴らしい新しいソリューション(2016年5月現在)があります。 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 %}
2
Jordan Lev

最初に私は思った、これは簡単に解決されるかもしれない-しかし、それは簡単ではありません。

twigサブテンプレートを含める場合と含めない場合は、おそらくphpクラスメソッドを使用して、ロジックを作成する必要があります。

<!-- 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ループ変数 を使用できます。これは、twigfor loop。しかし、このloop変数のスコープについてはわかりません。

解決策ではなくアプローチのみを提供して申し訳ありませんが、おそらく私の考えがあなたに役立つことを願っています(少し)。

この情報およびその他の情報は、 Twigs "for" Doc で入手できます。

1
domi27

インフルエンザの答えを取り、少し修正しました:

{# 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) }}
0

ここでの回答は、私のソリューションにつながります。

自己参照ManyToOneアソシエーション(親から子)を持つカテゴリエンティティがあります。

/**
 * @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>