PHPackages                             yiiext/nested-set-behavior - 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. yiiext/nested-set-behavior

ActiveYii-extension[Utility &amp; Helpers](/categories/utility)

yiiext/nested-set-behavior
==========================

AR models behavior that allows to work with nested sets tree.

v1.0.7(11y ago)158123.4k—7.1%62[5 issues](https://github.com/yiiext/nested-set-behavior/issues)1BSD-3-ClausePHPPHP &gt;=5.1.0

Since Jan 1Pushed 3y ago30 watchersCompare

[ Source](https://github.com/yiiext/nested-set-behavior)[ Packagist](https://packagist.org/packages/yiiext/nested-set-behavior)[ Docs](https://github.com/yiiext/nested-set-behavior)[ RSS](/packages/yiiext-nested-set-behavior/feed)WikiDiscussions master Synced yesterday

READMEChangelog (1)DependenciesVersions (2)Used By (1)

Nested Set
==========

[](#nested-set)

Nested Set behavior for Yii 2:

This extension allows managing trees stored in database as nested sets. It's implemented as Active Record behavior.

Installing and configuring
--------------------------

[](#installing-and-configuring)

First you need to configure model as follows:

```
public function behaviors()
{
    return array(
        'nestedSetBehavior'=>array(
            'class'=>'ext.yiiext.behaviors.model.trees.NestedSetBehavior',
            'leftAttribute'=>'lft',
            'rightAttribute'=>'rgt',
            'levelAttribute'=>'level',
        ),
    );
}
```

There is no need to validate fields specified in `leftAttribute`, `rightAttribute`, `rootAttribute` and `levelAttribute` options. Moreover, there could be problems if there are validation rules for these. Please check if there are no rules for fields mentioned in model's rules() method.

In case of storing a single tree per database, DB structure can be built with `extensions/yiiext/behaviors/trees/schema.sql`. If you're going to store multiple trees you'll need `extensions/yiiext/behaviors/trees/schema_many_roots.sql`.

By default `leftAttribute`, `rightAttribute` and `levelAttribute` values are matching field names in default DB schemas so you can skip configuring these.

There are two ways this behavior can work: one tree per table and multiple trees per table. The mode is selected based on the value of `hasManyRoots` option that is `false` by default meaning single tree mode. In multiple trees mode you can set `rootAttribute` option to match existing field in the table storing the tree.

Selecting from a tree
---------------------

[](#selecting-from-a-tree)

In the following we'll use an example model `Category` with the following in its DB:

```
- 1. Mobile phones
	- 2. iPhone
	- 3. Samsung
		- 4. X100
		- 5. C200
	- 6. Motorola
- 7. Cars
	- 8. Audi
	- 9. Ford
	- 10. Mercedes

```

In this example we have two trees. Tree roots are ones with ID=1 and ID=7.

### Getting all roots

[](#getting-all-roots)

Using `NestedSetBehavior::roots()`:

```
$roots=Category::model()->roots()->findAll();
```

Result:

Array of Active Record objects corresponding to Mobile phones and Cars nodes.

### Getting all descendants of a node

[](#getting-all-descendants-of-a-node)

Using `NestedSetBehavior::descendants()`:

```
$category=Category::model()->findByPk(1);
$descendants=$category->descendants()->findAll();
```

Result:

Array of Active Record objects corresponding to iPhone, Samsung, X100, C200 and Motorola.

### Getting all children of a node

[](#getting-all-children-of-a-node)

Using `NestedSetBehavior::children()`:

```
$category=Category::model()->findByPk(1);
$descendants=$category->children()->findAll();
```

Result:

Array of Active Record objects corresponding to iPhone, Samsung and Motorola.

### Getting all ancestors of a node

[](#getting-all-ancestors-of-a-node)

Using `NestedSetBehavior::ancestors()`:

```
$category=Category::model()->findByPk(5);
$ancestors=$category->ancestors()->findAll();
```

Result:

Array of Active Record objects corresponding to Samsung and Mobile phones.

### Getting parent of a node

[](#getting-parent-of-a-node)

Using `NestedSetBehavior::parent()`:

```
$category=Category::model()->findByPk(9);
$parent=$category->parent()->find();
```

Result:

Array of Active Record objects corresponding to Cars.

### Getting node siblings

[](#getting-node-siblings)

Using `NestedSetBehavior::prev()` or `NestedSetBehavior::next()`:

```
$category=Category::model()->findByPk(9);
$nextSibling=$category->next()->find();
```

Result:

Array of Active Record objects corresponding to Mercedes.

### Getting the whole tree

[](#getting-the-whole-tree)

You can get the whole tree using standard AR methods like the following.

For single tree per table:

```
Category::model()->findAll(array('order'=>'lft'));
```

For multiple trees per table:

```
Category::model()->findAll(array('condition'=>'root=?','order'=>'lft'),array($root_id));
```

Modifying a tree
----------------

[](#modifying-a-tree)

In this section we'll build a tree like the one used in the previous section.

### Creating root nodes

[](#creating-root-nodes)

You can create a root node using `NestedSetBehavior::saveNode()`. In a single tree per table mode you can create only one root node. If you'll attempt to create more there will be CException thrown.

```
$root=new Category;
$root->title='Mobile Phones';
$root->saveNode();
$root=new Category;
$root->title='Cars';
$root->saveNode();
```

Result:

```
- 1. Mobile Phones
- 2. Cars

```

### Adding child nodes

[](#adding-child-nodes)

There are multiple methods allowing you adding child nodes. To get more info about these refer to API. Let's use these to add nodes to the tree we have:

```
$category1=new Category;
$category1->title='Ford';
$category2=new Category;
$category2->title='Mercedes';
$category3=new Category;
$category3->title='Audi';
$root=Category::model()->findByPk(1);
$category1->appendTo($root);
$category2->insertAfter($category1);
$category3->insertBefore($category1);
```

Result:

```
- 1. Mobile phones
	- 3. Audi
	- 4. Ford
	- 5. Mercedes
- 2. Cars

```

Logically the tree above doesn't looks correct. We'll fix it later.

```
$category1=new Category;
$category1->title='Samsung';
$category2=new Category;
$category2->title='Motorola';
$category3=new Category;
$category3->title='iPhone';
$root=Category::model()->findByPk(2);
$category1->appendTo($root);
$category2->insertAfter($category1);
$category3->prependTo($root);
```

Result:

```
- 1. Mobile phones
	- 3. Audi
	- 4. Ford
	- 5. Mercedes
- 2. Cars
	- 6. iPhone
	- 7. Samsung
	- 8. Motorola

```

```
$category1=new Category;
$category1->title='X100';
$category2=new Category;
$category2->title='C200';
$node=Category::model()->findByPk(3);
$category1->appendTo($node);
$category2->prependTo($node);
```

Result:

```
- 1. Mobile phones
	- 3. Audi
		- 9. С200
		- 10. X100
	- 4. Ford
	- 5. Mercedes
- 2. Cars
	- 6. iPhone
	- 7. Samsung
	- 8. Motorola

```

Modifying a tree
----------------

[](#modifying-a-tree-1)

In this section we'll finally make our tree logical.

### Tree modification methods

[](#tree-modification-methods)

There are several methods allowing you to modify a tree. To get more info about these refer to API.

Let's start:

```
// move phones to the proper place
$x100=Category::model()->findByPk(10);
$c200=Category::model()->findByPk(9);
$samsung=Category::model()->findByPk(7);
$x100->moveAsFirst($samsung);
$c200->moveBefore($x100);
// now move all Samsung phones branch
$mobile_phones=Category::model()->findByPk(1);
$samsung->moveAsFirst($mobile_phones);
// move the rest of phone models
$iphone=Category::model()->findByPk(6);
$iphone->moveAsFirst($mobile_phones);
$motorola=Category::model()->findByPk(8);
$motorola->moveAfter($samsung);
// move car models to appropriate place
$cars=Category::model()->findByPk(2);
$audi=Category::model()->findByPk(3);
$ford=Category::model()->findByPk(4);
$mercedes=Category::model()->findByPk(5);

foreach(array($audi,$ford,$mercedes) as $category)
    $category->moveAsLast($cars);
```

Result:

```
- 1. Mobile phones
	- 6. iPhone
	- 7. Samsung
		- 10. X100
		- 9. С200
	- 8. Motorola
- 2. Cars
	- 3. Audi
	- 4. Ford
	- 5. Mercedes

```

### Moving a node making it a new root

[](#moving-a-node-making-it-a-new-root)

There is a special `moveAsRoot()` method that allows moving a node and making it a new root. All descendants are moved as well in this case.

Example:

```
$node=Category::model()->findByPk(10);
$node->moveAsRoot();
```

### Identifying node type

[](#identifying-node-type)

There are three methods to get node type: `isRoot()`, `isLeaf()`, `isDescendantOf()`.

Example:

```
$root=Category::model()->findByPk(1);
CVarDumper::dump($root->isRoot()); //true;
CVarDumper::dump($root->isLeaf()); //false;
$node=Category::model()->findByPk(9);
CVarDumper::dump($node->isDescendantOf($root)); //true;
CVarDumper::dump($node->isRoot()); //false;
CVarDumper::dump($node->isLeaf()); //true;
$samsung=Category::model()->findByPk(7);
CVarDumper::dump($node->isDescendantOf($samsung)); //true;
```

Useful code
-----------

[](#useful-code)

### Non-recursive tree traversal

[](#non-recursive-tree-traversal)

```
$criteria=new CDbCriteria;
$criteria->order='t.lft'; // or 't.root, t.lft' for multiple trees
$categories=Category::model()->findAll($criteria);
$level=0;

foreach($categories as $n=>$category)
{
	if($category->level==$level)
		echo CHtml::closeTag('li')."\n";
	else if($category->level>$level)
		echo CHtml::openTag('ul')."\n";
	else
	{
		echo CHtml::closeTag('li')."\n";

		for($i=$level-$category->level;$i;$i--)
		{
			echo CHtml::closeTag('ul')."\n";
			echo CHtml::closeTag('li')."\n";
		}
	}

	echo CHtml::openTag('li');
	echo CHtml::encode($category->title);
	$level=$category->level;
}

for($i=$level;$i;$i--)
{
	echo CHtml::closeTag('li')."\n";
	echo CHtml::closeTag('ul')."\n";
}
```

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity50

Moderate usage in the ecosystem

Community30

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 64.4% 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

Unknown

Total

1

Last Release

4201d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/261a6249c6f605f3956a2fae40fbb813f6b2e1e6f2bf806180c851a965426e54?d=identicon)[cebe](/maintainers/cebe)

![](https://www.gravatar.com/avatar/fc29e4e7068a00fe9b9db37b8aadda1db6020adcacef810461e47b99c2b150e6?d=identicon)[samdark](/maintainers/samdark)

![](https://avatars.githubusercontent.com/u/896494?v=4)[Alexander Kochetov](/maintainers/creocoder)[@creocoder](https://github.com/creocoder)

---

Top Contributors

[![creocoder](https://avatars.githubusercontent.com/u/896494?v=4)](https://github.com/creocoder "creocoder (58 commits)")[![samdark](https://avatars.githubusercontent.com/u/47294?v=4)](https://github.com/samdark "samdark (15 commits)")[![boazrymland](https://avatars.githubusercontent.com/u/1311936?v=4)](https://github.com/boazrymland "boazrymland (5 commits)")[![cebe](https://avatars.githubusercontent.com/u/189796?v=4)](https://github.com/cebe "cebe (4 commits)")[![slavcodev](https://avatars.githubusercontent.com/u/757721?v=4)](https://github.com/slavcodev "slavcodev (4 commits)")[![farmani](https://avatars.githubusercontent.com/u/1329580?v=4)](https://github.com/farmani "farmani (2 commits)")[![SamMousa](https://avatars.githubusercontent.com/u/547021?v=4)](https://github.com/SamMousa "SamMousa (2 commits)")

---

Tags

extensionyiinested-set

### Embed Badge

![Health badge](/badges/yiiext-nested-set-behavior/health.svg)

```
[![Health](https://phpackages.com/badges/yiiext-nested-set-behavior/health.svg)](https://phpackages.com/packages/yiiext-nested-set-behavior)
```

###  Alternatives

[evgeniyrru/yii2-slick

Yii2 extension for Slick Carousel

22203.5k3](/packages/evgeniyrru-yii2-slick)

PHPackages © 2026

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