PHPackages                             webhappens/traverser - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. webhappens/traverser

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

webhappens/traverser
====================

Easily traverse nested object structures without worrying about recursion.

v0.3.3(1y ago)08.8k↓37.5%MITPHPPHP ^8.0CI passing

Since Mar 30Pushed 1y ago1 watchersCompare

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

READMEChangelogDependencies (3)Versions (7)Used By (0)

[![tests](https://github.com/webhappens/traverser/workflows/tests/badge.svg)](https://github.com/webhappens/traverser/workflows/tests/badge.svg)

Traverser
=========

[](#traverser)

Easily traverse nested object structures without worrying about recursion. Great for building menus, navigation, sitemaps and more!

- [Installation](#installation)
- [Getting started](#getting-started)
- [Custom mapping names](#custom-mapping-names)
- [Inferring parent and children](#inferring-parent-and-children)
- [Traversal methods](#traversal-methods)

Installation
------------

[](#installation)

Install via composer:

```
composer require webhappens/traverser
```

Import the class into your namespace:

```
use WebHappens\Traverser\Traverser;
```

Getting started
---------------

[](#getting-started)

In order for the traverser to understand your hierarchy, you must ensure it can resolve "id", "parent" and "children" for each class in that hierarchy.

By default, it will look for "methods" or "properties" (in that order) by each of these names. If your classes extend from `Illuminate\Database\Eloquent\Model` it will resolve the "id" automatically from the `getKey` method.

Your classes should typically look something like this:

```
public $id;

/**
 * @return object|null
 */
public function parent()
{
    //
}

/**
 * @return array
 */
public function children()
{
    //
}
```

Next, create a new instance of the traverser class and pass in an instance of the class you'd like to use as your starting point for traversal.

```
$traverser = Traverser::make($current);
```

You can now call the various traversal methods on this instance.

```
$descendants = $traverser->descendants();
```

As a convenience you might want to put this on a base class or trait:

```
// Within a base class or trait

public function traverser()
{
    return Traverser::make($this);
}
```

And then call it like this:

```
// Within a class that extends the base class / uses the trait

$this->traverser()->descendants();
```

For a deeper insight on using the traverser you should take a look at the tests.

Custom mapping names
--------------------

[](#custom-mapping-names)

You may override the default "id", "parent" and "children" mapping names for each class if you want to.

To do this pass a second argument into the constructor containing a custom mapping array.

```
$traverser = Traverser:make($current, [
    Page::class => ['id' => 'uri'],
    Post::class => ['parent' => 'category', 'children' => 'comments'],
    Comment::class => ['parent' => 'post'],
]);
```

If you're using Laravel you may want to bind this to the Service Container.

```
// Within AppServiceProvider.php

$this->app->bind('traverser', function () {
    return \WebHappens\Traverser\Traverser::make()->maps([...]);
});
```

And then resolve it like this:

```
// Within your application code

$traverser = resolve('traverser')->current($current);
```

Note that you can construct a new traverser instance without passing any arguments and use the `maps` and `current` methods instead.

Inferring parent and children
-----------------------------

[](#inferring-parent-and-children)

In most situations your objects will only have data about who their "parent" is or who their "children" are, not both. For this reason the traverser allows you to easily infer one from the other.

To infer parent you should pass an array of all possible parents into the `inferParent` method. Each of these objects must be able to resolve its own children.

```
// Within Category.php

public function parent()
{
    return $this->traverser()->inferParent(static::all());
}

public function children()
{
    return array_merge($this->categories(), $this->posts());
}

// Within Post.php

public function category()
{
    return $this->traverser()->inferParent(Category::all());
}
```

To infer children you should pass an array of all possible children into the `inferChildren` method. Each of these objects must be able to resolve its own parent.

```
// Within Page.php

public function parent()
{
    // ...
    return new static($parentId);
}

public function children()
{
    return $this->traverser()->inferChildren(static::all());
}
```

Traversal methods
-----------------

[](#traversal-methods)

```
$parent = $this->traverser()->parent();
$children = $this->traverser()->children();
$ancestors = $this->traverser()->ancestors();
$ancestorsAndSelf = $this->traverser()->ancestorsAndSelf();
$descendants = $this->traverser()->descendants();
$descendantsAndSelf = $this->traverser()->descendantsAndSelf();
$siblings = $this->traverser()->siblings();
$siblingsAndSelf = $this->traverser()->siblingsAndSelf();
$siblingsNext = $this->traverser()->siblingsNext();
$siblingsAfter = $this->traverser()->siblingsAfter();
$siblingsPrevious = $this->traverser()->siblingsPrevious();
$siblingsBefore = $this->traverser()->siblingsBefore();
$siblingsPosition = $this->traverser()->siblingsPosition();
```

Credits
-------

[](#credits)

- Ben Gurney:
- Sam Leicester:
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance46

Moderate activity, may be stable

Popularity24

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 56.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~363 days

Recently: every ~379 days

Total

6

Last Release

421d ago

PHP version history (3 changes)v0.1.0PHP ^7.1.3

v0.2.0PHP ^7.3|^8.0

v0.3.0PHP ^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/319829?v=4)[Sam Leicester](/maintainers/sleicester)[@sleicester](https://github.com/sleicester)

---

Top Contributors

[![bgurney](https://avatars.githubusercontent.com/u/6359858?v=4)](https://github.com/bgurney "bgurney (30 commits)")[![sleicester](https://avatars.githubusercontent.com/u/319829?v=4)](https://github.com/sleicester "sleicester (23 commits)")

---

Tags

treetraversalwebhappens

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/webhappens-traverser/health.svg)

```
[![Health](https://phpackages.com/badges/webhappens-traverser/health.svg)](https://phpackages.com/packages/webhappens-traverser)
```

###  Alternatives

[knplabs/knp-menu

An object oriented menu library

1.4k55.8M287](/packages/knplabs-knp-menu)[cuyz/valinor

Dependency free PHP library that helps to map any input into a strongly-typed structure.

1.5k9.2M108](/packages/cuyz-valinor)[bluem/tree

Library for handling tree structures based on parent IDs

252916.1k7](/packages/bluem-tree)[codewithdennis/filament-select-tree

The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.

320392.1k17](/packages/codewithdennis-filament-select-tree)[kartik-v/yii2-tree-manager

An enhanced tree management module with tree node selection and manipulation using nested sets.

156529.0k15](/packages/kartik-v-yii2-tree-manager)[chdemko/sorted-collections

Sorted Collections for PHP &gt;= 8.2

222.5M3](/packages/chdemko-sorted-collections)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
