PHPackages                             rezozero/tree-walker - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. rezozero/tree-walker

ActiveLibrary

rezozero/tree-walker
====================

Creates a configurable tree walker using different methods for each node based on its PHP class or interface

1.7.0(3mo ago)112.6k↓45.8%3MITPHPPHP &gt;=8.2CI passing

Since Jun 1Pushed 3mo ago3 watchersCompare

[ Source](https://github.com/rezozero/tree-walker)[ Packagist](https://packagist.org/packages/rezozero/tree-walker)[ RSS](/packages/rezozero-tree-walker/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (9)Versions (35)Used By (3)

Tree Walker
===========

[](#tree-walker)

[![Tests status](https://github.com/rezozero/tree-walker/actions/workflows/run-test.yml/badge.svg)](https://github.com/rezozero/tree-walker/actions/workflows/run-test.yml) [![License](https://camo.githubusercontent.com/983b830a7ca1046c98084fb90a40c6f9c599851ade288e16d9476a7f3e95bab6/687474703a2f2f696d672e736869656c64732e696f2f3a6c6963656e73652d6d69742d626c75652e7376673f7374796c653d666c6174)](https://camo.githubusercontent.com/983b830a7ca1046c98084fb90a40c6f9c599851ade288e16d9476a7f3e95bab6/687474703a2f2f696d672e736869656c64732e696f2f3a6c6963656e73652d6d69742d626c75652e7376673f7374796c653d666c6174) [![Packagist](https://camo.githubusercontent.com/95b8b44ce4de97fc2d9a68d539d1e75038eb6da69ac05ff30e5b88772eb5521d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f72657a6f7a65726f2f747265652d77616c6b65722e7376673f7374796c653d666c6174)](https://packagist.org/packages/rezozero/tree-walker)

**Creates a configurable tree walker using different definitions for each node based on its PHP class or interface.**

`WalkerInterface` implements `\Countable` in order to use it seamlessly in your PHP code and Twig templates. Each `WalkerInterface` will carry your *node* object and its children.

Since v1.1.0 `AbstractWalker` does not implement `\IteratorAggregate` in order to be compatible with *api-platform* normalizer (it normalizes it as a Hydra:Collection). But if you need it in you can add `\IteratorAggregate` to your custom Walker implementation, `getIterator` is already implemented.

If your application may introduce cyclic references between objects, you can use `AbstractCycleAwareWalker` instead of `AbstractWalker` to keep track of collected items and prevent collecting same item children twice. Collision detection is based on `spl_object_id` method.

Table of Contents
-----------------

[](#table-of-contents)

- [Usage in Twig](#usage-in-twig)
    - [Walk forward](#walk-forward)
    - [Walk backward](#walk-backward)
- [Configure your Walker](#configure-your-walker)
- [Serialization groups](#serialization-groups)
- [Stoppable definition](#stoppable-definition)

Usage in Twig
-------------

[](#usage-in-twig)

- First, make sure your Walker instance implements `\IteratorAggregate` in order to use it directly into a loop

### Walk forward

[](#walk-forward)

Here is an example of a **recursive** navigation item template using our `WalkerInterface`:

```
{# nav-item.html.twig #}

    {{ item.title }}
    {#
     # Walker object must be your general navigation WalkerInterface
     # and current page must be inside navigation graph.
     #
     # getWalkerAtItem method looks for current page in your Walker
     # and returns walker interface for current page.
     #}
    {# Always a good idea to check walker item count before going further #}
    {% if walker and walker|length %}

                {% for subWalker in walker %}
                    {% include 'nav-item.html.twig' with {
                        'walker': subWalker,
                        'item' : subWalker.item,
                    } only %}
                {% endfor %}

    {% endif %}

```

### Walk backward

[](#walk-backward)

You can *reverse* walk (aka *moon walking*) to display a page breadcrumbs for example:

```
{# page.html.twig #}

{% macro walkBreadcrumbs(pageWalker) %}
    {% if pageWalker.parent %}
        {% set pageWalker = pageWalker.parent %}
        {# Recursive magic here … #}
        {{ _self.walkBreadcrumbs(pageWalker) }}
        {# Call macro itself before displaying to keep ancestors first #}
        {% if pageWalker.item is not Neutral %}

                {{ pageWalker.item.title }}

        {% endif %}
    {% endif %}
{% endmacro %}

    {#
     # walker object must be your general navigation WalkerInterface
     # and current page must be inside navigation graph.
     #
     # getWalkerAtItem method looks for current page in your Walker
     # and returns walker interface for current page.
     #}
    {% set pageWalker = walker.getWalkerAtItem(page) %}

    {# Recursive magic here … #}
    {{ _self.walkBreadcrumbs(pageWalker.getParent) }}

    {{ page.title }}

```

Configure your Walker
---------------------

[](#configure-your-walker)

1. Create a `WalkerContextInterface` instance to hold every service your `callable` definitions will use to fetch each tree node children. For example: a *Doctrine repository*, a *QueryBuilder*, even your *PDO* instance.
2. Create a custom *Walker* class **extending** `AbstractWalker`.
    You’ll notice that `AbstractWalker` is very strict and prevents overriding its *constructor* in order to abstract all `WalkerInterface` instantiations from your business logic. **All your custom logic must be included in `definitions` and `countDefinitions`.**
3. Add `definitions` and `countDefinitions` from your custom *Walker*. A *definition* `callable` must return an `array` (or an *iterable* object) of your items. A *countDefinition* `callable` must return an `int` representing your items number. *CountDefinitions* are optional: `AbstractWalker::count()` method will fall back on using `AbstractWalker::getChildren()->count()`.
4. Instantiate your custom Walker with your root item, and your context object

Here is some pseudo PHP code example:

```
