PHPackages                             stefano/stefano-tree - 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. [Database &amp; ORM](/categories/database)
4. /
5. stefano/stefano-tree

ActiveLibrary[Database &amp; ORM](/categories/database)

stefano/stefano-tree
====================

Nested Set(MPTT) implementation for PHP

5.0.0(3y ago)2788.5k↓33.3%8[5 issues](https://github.com/bartko-s/stefano-tree/issues)BSD-3-ClausePHPPHP &gt;=7.1.0

Since May 27Pushed 2y ago2 watchersCompare

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

READMEChangelogDependencies (8)Versions (44)Used By (0)

Tree
====

[](#tree)

[![Latest Stable Version](https://camo.githubusercontent.com/41da108eaf8cf2e0f39bf9cf6a1da9cdccbbbc0d8a6055eafa62a71b29bd9201/68747470733a2f2f706f7365722e707567782e6f72672f73746566616e6f2f73746566616e6f2d747265652f76657273696f6e)](https://packagist.org/packages/stefano/stefano-tree)[![Build Status](https://camo.githubusercontent.com/f8660eb12b8dc7f6803f8aa3c207a7a554033b2730405ae5c476bea3643b5830/68747470733a2f2f6170702e7472617669732d63692e636f6d2f626172746b6f2d732f73746566616e6f2d747265652e7376673f6272616e63683d6d6173746572)](https://app.travis-ci.com/bartko-s/stefano-tree)[![Coverage Status](https://camo.githubusercontent.com/2e42294aa63c36cf3ad7cbcbcf1d3116040151d4b801b0b6095d0cb4d2be945a/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f626172746b6f2d732f73746566616e6f2d747265652f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/github/bartko-s/stefano-tree?branch=master)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/6e99c5db23341c23e4edf742af742740cd8295a501962bcd7de9794066a5d393/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f626172746b6f2d732f73746566616e6f2d747265652f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/bartko-s/stefano-tree/?branch=master)[![License](https://camo.githubusercontent.com/3de2374acc93da61deeafe57d1149053ceed068864fcec72ecc35835b69382f3/68747470733a2f2f706f7365722e707567782e6f72672f73746566616e6f2f73746566616e6f2d747265652f6c6963656e7365)](https://packagist.org/packages/stefano/stefano-tree)[![Total Downloads](https://camo.githubusercontent.com/cdf6f874eb08986a11a8b1e09fff7842e55af1d329e1d90332c4920ee33bc072/68747470733a2f2f706f7365722e707567782e6f72672f73746566616e6f2f73746566616e6f2d747265652f646f776e6c6f616473)](https://packagist.org/packages/stefano/stefano-tree)[![Monthly Downloads](https://camo.githubusercontent.com/deed75870602674949511c540033848b9582408d7e34d6590e03619035d16b87/68747470733a2f2f706f7365722e707567782e6f72672f73746566616e6f2f73746566616e6f2d747265652f642f6d6f6e74686c79)](https://packagist.org/packages/stefano/stefano-tree)

[![Buy me a coffee](./doc/buy-me-a-coffe.png)](https://www.buymeacoffee.com/bartko)

[![Donate on PayPal](https://camo.githubusercontent.com/e1ff554a09e8e92bef25abc553ff05b88f45afd695877cf12f3a46558ef65b2e/68747470733a2f2f7777772e70617970616c6f626a656374732e636f6d2f656e5f55532f692f62746e2f62746e5f646f6e61746543435f4c472e676966)](https://paypal.me/stevo4)

[Nested Set](https://en.wikipedia.org/wiki/Nested_set_model) implementation for PHP.

[![Live demo](./doc/live-demo.jpg)](https://www.tree.stefanbartko.sk)

Features
--------

[](#features)

- NestedSet(MPTT - Modified Pre-order Tree Traversal)
- Support scopes (multiple independent tree in one db table)
- Rebuild broken tree
- Tested with MySQL/MariaDB and PostgreSQL but should work with any database vendor which support transaction
- Supported [PDO](http://php.net/manual/en/intro.pdo.php), [Zend Framework 1](https://framework.zend.com/manual/1.12/en/zend.db.html), [Laminas Db](https://github.com/laminas/laminas-db), [Doctrine 2 DBAL and Doctrine 3 DBAL](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/). It is easy to implement support for any framework
- Support nested transaction
- PHP 7 and PHP 8 support

Dependencies
------------

[](#dependencies)

- This library has no external dependencies. Can work with pure PHP.

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

[](#installation)

Run following command in terminal

```
composer require stefano/stefano-tree

```

Create Tree Adapter
-------------------

[](#create-tree-adapter)

keytyperequireddefault valuenotetableNamestringyesidColumnNamestringyesleftColumnNamestringnolftrightColumnNamestringnorgtlevelColumnNamestringnolevelparentIdColumnNamestringnoparent\_idsequenceNamestringsee noteRequired for PostgreSQLscopeColumnNamestringsee noteIf empty scope support is disableddbSelectBuildercallablenosee Join table example below```
use \StefanoTree\NestedSet;

$options = array(
    'tableName'    => 'tree_traversal',
    'idColumnName' => 'tree_traversal_id',
    // other options
);

$dbAdapter = pure \PDO, Zend1 Db Adapter, Laminas Db Adapter, Doctrine DBAL Connection or any class which implements StefanoTree\NestedSet\Adapter\AdapterInterface interface

$tree = new NestedSet($options, $dbAdapter);

```

- You can join table.

```
$options = array(
    'tableName'       => 'tree_traversal',
    'idColumnName'    => 'tree_traversal_id',
    'dbSelectBuilder' => function() {
         // You can use any "callable" like function or object
         // Select must be without where or order part
         return 'SELECT tree_traversal.*, m.something, ...'
           .' FROM tree_traversal'
           .' LEFT JOIN metadata AS m ON tree_traversal.id=m.tree_id';
     },
    // other options
);

$tree = new NestedSet($options, $dbAdapter);

```

API
---

[](#api)

### Creating nodes

[](#creating-nodes)

- Create root node

```
use StefanoTree\Exception\ValidationException;

try {
    $data = array(
        // values
        // id_column_name => uuid
    );

    // create root node.
    $rootNodeId = $tree->createRootNode($data);

    // create root node. Second param "$scope" is required only if scope support is enabled.
    $rootNodeId = $tree->createRootNode($data, $scope);
} catch (ValidationException $e) {
    $errorMessage = $e->getMessage();
}

```

- Create new node. You can create new node at 4 different locations.

[![placements](./doc/placements.png)](./doc/placements.png)

```
use StefanoTree\Exception\ValidationException;

try {
    $targetNodeId = 10;

    $data = array(
        // values
        // id_column_name => uuid
    );

    $nodeId = $tree->addNode($targetNodeId, $data, $tree::PLACEMENT_CHILD_TOP);
    $nodeId = $tree->addNode($targetNodeId, $data, $tree::PLACEMENT_CHILD_BOTTOM);
    $nodeId = $tree->addNode($targetNodeId, $data, $tree::PLACEMENT_TOP);
    $nodeId = $tree->addNode($targetNodeId, $data, $tree::PLACEMENT_BOTTOM);
} catch (ValidationException $e) {
    $errorMessage = $e->getMessage();
}

```

### Update Node

[](#update-node)

```
use StefanoTree\Exception\ValidationException;

try {
    $targetNodeId = 10;

    $data = array(
        // values
    );

    $tree->updateNode($targetNodeId, $data);
} catch (ValidationException $e) {
    $errorMessage = $e->getMessage();
}

```

### Move node

[](#move-node)

- You can move node at 4 different locations.

[![placements](./doc/placements.png)](./doc/placements.png)

```
use StefanoTree\Exception\ValidationException;

try {
    $sourceNodeId = 15;
    $targetNodeId = 10;

    $tree->moveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_CHILD_TOP);
    $tree->moveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_CHILD_BOTTOM);
    $tree->moveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_TOP);
    $tree->moveNode($sourceNodeId, $targetNodeId, $tree::PLACEMENT_BOTTOM);
} catch (ValidationException $e) {
    $errorMessage = $e->getMessage();
}

```

### Delete node or branch

[](#delete-node-or-branch)

```
use StefanoTree\Exception\ValidationException;

try {
    $nodeId = 15;

    $tree->deleteBranch($nodeId);
} catch (ValidationException $e) {
    $errorMessage = $e->getMessage();
}

```

### Getting nodes

[](#getting-nodes)

- Get descendants

```
$nodeId = 15;

// all descendants
$tree->getDescendantsQueryBuilder()
     ->get($nodeId);

// all descendants result as nested array
$tree->getDescendantsQueryBuilder()
     ->get($nodeId, true);

// only children
$tree->getDescendantsQueryBuilder()
     ->excludeFirstNLevel(1)
     ->levelLimit(1)
     ->get($nodeId);

// exclude first level($nodeId) from result
$tree->getDescendants()
     ->excludeFirstNLevel(1)
     ->get($nodeId);

// exclude first two levels from result
$tree->getDescendantsQueryBuilder()
     ->excludeFirstNLevel(2)
     ->get($nodeId);

// return first 4 level
$tree->getDescendantsQueryBuilder()
     ->levelLimit(4)
     ->get($nodeId);

// exclude branch from  result
$tree->getDescendantsQueryBuilder()
     ->excludeBranch(22)
     ->get($nodeId);

```

- Get Ancestors

```
$nodeId = 15;

// get all
$tree->getAncestorsQueryBuilder()
     ->get($nodeId);

// get all as nested array
$tree->getAncestorsQueryBuilder()
     ->get($nodeId, true);

// exclude last node($nodeId) from result
$tree->getAncestorsQueryBuilder()
     ->excludeLastNLevel(1)
     ->get($nodeId);

// exclude first two levels from result
$tree->getAncestorsQueryBuilder()
     ->excludeFirstNLevel(2)
     ->get($nodeId);

```

### Validation and Rebuild broken tree

[](#validation-and-rebuild-broken-tree)

- Check if tree is valid

```
use StefanoTree\Exception\ValidationException;

try {
    $satus = $tree->isValid($rootNodeId);
} catch (ValidationException $e) {
    $errorMessage = $e->getMessage();
}

```

- Rebuild broken tree

```
use StefanoTree\Exception\ValidationException;

try {
    $tree->rebuild($rootNodeId);
} catch (ValidationException $e) {
    $errorMessage = $e->getMessage();
}

```

Contributing
------------

[](#contributing)

Any contributions are welcome. If you find any issue don't hesitate to open a new issue or send a pull request.

[![Buy me a coffee](./doc/buy-me-a-coffe.png)](https://www.buymeacoffee.com/bartko)

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance16

Infrequent updates — may be unmaintained

Popularity42

Moderate usage in the ecosystem

Community16

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 98.2% 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 ~83 days

Recently: every ~264 days

Total

42

Last Release

1327d ago

Major Versions

1.6.1 → 2.0.02016-11-17

2.0.2 → 3.0.02017-12-27

3.1.2 → 4.0.02018-07-23

4.2.1 → 5.0.02022-09-29

PHP version history (4 changes)1.0.0PHP &gt;=5.3.0

1.5.1PHP &gt;=5.5.0

1.5.2PHP &gt;=5.6.0

3.0.0PHP &gt;=7.1.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/12da8e2ce2685d50df256c7d302dff9de0eeab90057103170ec1c840d26eed19?d=identicon)[Stefano123](/maintainers/Stefano123)

---

Top Contributors

[![bartko-s](https://avatars.githubusercontent.com/u/675883?v=4)](https://github.com/bartko-s "bartko-s (324 commits)")[![tomasfejfar](https://avatars.githubusercontent.com/u/642928?v=4)](https://github.com/tomasfejfar "tomasfejfar (4 commits)")[![CodeLingoBot](https://avatars.githubusercontent.com/u/45469328?v=4)](https://github.com/CodeLingoBot "CodeLingoBot (1 commits)")[![tsmgeek](https://avatars.githubusercontent.com/u/5859988?v=4)](https://github.com/tsmgeek "tsmgeek (1 commits)")

---

Tags

doctrine-dbaldoctrine2hierarchical-datalaminaslaminas-dbmpttnested-setpdotreetree-structurezend-frameworksymfonylaminasdoctrinepdozendtreeZend Frameworknested-setdoctrine-dbalMPTTlaminas db

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/stefano-stefano-tree/health.svg)

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

###  Alternatives

[samsonasik/error-hero-module

A Hero for your Laminas and Mezzio application to trap php errors &amp; exceptions

5233.4k1](/packages/samsonasik-error-hero-module)[redcode/tree-bundle

This Symfony bundle integrates jsTree and Gedmo Nested Set directly to Sonata Admin

3048.5k](/packages/redcode-tree-bundle)[ambta/doctrine-encrypt-bundle

Symfony 2 bundle which allows to encrypt data in database with some encrypt algorithm

77275.7k](/packages/ambta-doctrine-encrypt-bundle)[zfc-datagrid/zfc-datagrid

Laminas Module that provides a datagrid for different datasources and output formats

1223.2k](/packages/zfc-datagrid-zfc-datagrid)[prezent/doctrine-translatable-bundle

Integrate the doctrine-translatable extension in Symfony

14698.4k5](/packages/prezent-doctrine-translatable-bundle)

PHPackages © 2026

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