Framework agnostic library for managing tree structures

2.0.2 2017-04-24 15:27 UTC


Test Status Code Coverage Quality Dependencies
Test Status Code Coverage Scrutinizer Code Quality Dependency Status

Nested Set implementation for PHP.



  • NestedSet(MPTT - Modified Preorder Tree Traversal)
  • Support scopes (multiple independent tree in one db table)
  • Rebuild broken tree
  • Tested with MySQL and PostgreSQL but should work with any database vendor which support transaction
  • Support Frameworks Zend Framework 1, Zend Framework 2, Doctrine 2 DBAL, Stefano Db
  • It is easy to implement support for any framework


  • Stefano Tree has no external dependencies only Php and your framework is required


  1. Add following line to your composer.json file "stefano/stefano-tree": "~2.0.0"
  2. Create db scheme example db scheme. Name of table, columns are fully customizable.
  3. Create tree adapter
  • Use static factory method
$options = new \StefanoTree\NestedSet\Options(array(
    'tableName'    => 'tree_traversal', //required
    'idColumnName' => 'tree_traversal_id', //required
    'leftColumnName' => 'lft', //optional (default lft)
    'rightColumnName' => 'rgt', //optional (default rgt)
    'levelColumnName' => 'level', //optional (default level)
    'parentIdColumnName' => 'parent_id', //optional (default parent_id)
    'sequenceName' => 'sequence_name_seq', //required for PostgreSQL
    'scopeColumnName' => 'scope', //optional

$dbAdapter = ... supported db adapter ...

$tree = \StefanoTree\NestedSet::factory($options, $dbAdapter);
  • or create tree adapter directly
$options = new \StefanoTree\NestedSet\Options(array(...);

$dbAdapter = ... supported db adapter ...

$nestedSetAdapter = new \StefanoTree\NestedSet\Adapter\Zend2($options, $dbAdapter);

$tree = new \StefanoTree\NestedSet($nestedSetAdapter);
  • You can join table. Example is for Zend Framework 2 but it works similar for other supported frameworks.
$defaultDbSelect = $nestedSetAdapter->getDefaultDbSelect();

//zend framework select object
$defaultDbSelect->join($name, $on, $columns, $type);


Creating nodes

  • Create root node
// create root node. Scope support is disabled

// create root node. Scope support is enabled
$tree->createRootNode(array(), $scope);
  • Create new node
$targetNodeId = 10;

$data = array(

$tree->addNodePlacementBottom($targetNodeId, $data);
$tree->addNodePlacementTop($targetNodeId, $data);
$tree->addNodePlacementChildBottom($targetNodeId, $data);
$tree->addNodePlacementTop($targetNodeId, $data);

Update Node

$targetNodeId = 10;

$data = array(

$tree->updateNode($targetNodeId, $data);

Move node

$sourceNodeId = 15;
$targetNodeId = 10;

$tree->moveNodePlacementBottom($sourceNodeId, $targetNodeId);
$tree->moveNodePlacementTop($sourceNodeId, $targetNodeId);
$tree->moveNodePlacementChildBottom($sourceNodeId, $targetNodeId);
$tree->moveNodePlacementChildTop($sourceNodeId, $targetNodeId);

Delete node or branch

$nodeId = 15;


Getting nodes

  • Get all children
$nodeId = 15;
  • Get all descendants
$nodeId = 15;

//all descedants

//exclude node $nodeId from result
$tree->getDescendants($nodeId, 1);

//exclude first two levels from result
$tree->getDescendants($nodeId, 2);

//get four levels
$tree->getDescendants($nodeId, 0, 4);
  • Exclude branche from result
$nodeId = 15;
$excludeBranche = 22;
$tree->getDescendants($nodeId, 0, null, $excludeBranche);
  • Get Path
$nodeId = 15;

//full path

//exclude node $nodeId from result
$tree->getPath($nodeId, 1);

//exclude first two levels from result
$tree->getPath($nodeId, 2);

//exclude last node
$tree->getPath($nodeId, 0, true);

Validation and Rebuild broken tree

  • Check if tree is valid
  • Rebuild broken tree

Helping project

If this project helps you reduce time to develop and/or you want to help the maintainer of this project, you can make a donation. Thank you.