f63b4691e7
Fixed parent class for MysqlNestedSetsQueryBehaviorTest |
||
---|---|---|
src | ||
tests | ||
.gitignore | ||
.scrutinizer.yml | ||
.travis.yml | ||
composer.json | ||
composer.lock | ||
LICENSE.md | ||
phpunit.xml.dist | ||
README.md |
Nested Sets Behavior for Yii 2
A modern nested sets behavior for the Yii framework utilizing the Modified Preorder Tree Traversal algorithm.
Quick Example
Making a root node
$countries = new Menu(['name' => 'Countries']);
$countries->makeRoot();
Make a node as the last child of another node
$australia = new Menu(['name' => 'Australia']);
$australia->appendTo($countries);
The tree will look like this
- Countries
- Australia
Make a node as the first child of another node
$russia = new Menu(['name' => 'Russia']);
$russia->prependTo($countries);
The tree will look like this
- Countries
- Russia
- Australia
Insert a node before another node
$newZeeland = new Menu(['name' => 'New Zeeland']);
$newZeeland->insertBefore($australia);
The tree will look like this
- Countries
- Russia
- New Zeeland
- Australia
Insert a node after another node
$unitedStates = new Menu(['name' => 'United States']);
$unitedStates->insertAfter($australia);
The tree will look like this
- Countries
- Russia
- New Zeeland
- Australia
- United States
Installation
The preferred way to install this extension is through composer.
Either run
$ php composer.phar require creocoder/yii2-nested-sets:dev-master
or add
"creocoder/yii2-nested-sets": "dev-master"
to the require
section of your composer.json
file.
Configuring
Configure model as follows
use creocoder\nestedsets\NestedSetsBehavior;
class Tree extends \yii\db\ActiveRecord
{
public function behaviors() {
return [
NestedSetsBehavior::className(),
];
}
public function transactions()
{
return [
self::SCENARIO_DEFAULT => self::OP_ALL,
];
}
public static function find()
{
return new TreeQuery(get_called_class());
}
}
Single Tree mode
Configure query class as follows
use creocoder\nestedsets\NestedSetsQueryBehavior;
class TreeQuery extends \yii\db\ActiveQuery
{
public function behaviors() {
return [
NestedSetsQueryBehavior::className(),
];
}
}
The model has to have several fields. The fields that need to be set up are:
-
lft
, type integer. If you do not want to use this default name you can change it by setting up theleftAttribute
attribute. The example assumes that you want to change the name toleft
public function behaviors() { return [ 'nestedSets' => [ 'class' => NestedSetsBehavior::className(), 'leftAttribute' => 'left', ], ]; }
-
rgt
, type integer. To change the name of the field make the same setting as for lft, but use the attributerightAttribute
-
depth
, type integer. To change the name of the field make the same setting as for lft, but use the attributedepthAttribute
Multiple Tree mode
If you use a tree with multiple roots, besides the fields set up for the single tree, you have to set up an additional
field. The type of the new field is integer. The following example is for a tree attribute field named root
public function behaviors() {
return [
'nestedSets' => [
'class' => NestedSetsBehavior::className(),
'treeAttribute' => 'root',
],
];
}
Migration examples
This is an example migration to create a table for a model (with multiple roots) and all the fields necessary for the extension
$this->createTable('{{%menu}}', [
'id' => Schema::TYPE_PK,
'root' => Schema::TYPE_INTEGER,
'lft' => Schema::TYPE_INTEGER . ' NOT NULL',
'rgt' => Schema::TYPE_INTEGER . ' NOT NULL',
'depth' => Schema::TYPE_INTEGER . ' NOT NULL',
//...
]);
If you are using a model with a single node you should remove the root field as it is unnecessary.
Advanced Usage
Getting the root nodes
To get all the root nodes
$roots = Menu::find()->roots()->all();
foreach($roots as $root) {
echo $root->name;
}
Getting the leaves nodes
To get all the leaves nodes
$leaves = Menu::find()->leaves()->all();
foreach($leaves as $leaf) {
echo $leaf->name;
}
To get all the leaves of a node
$countries = Menu::findOne(['name' => 'Countries']);
$leaves = $countries->leaves()->all();
foreach($leaves as $leaf) {
echo $leaf->name;
}
Getting children of a node
To get all the children of a node
$countries = Menu::findOne(['name' => 'Countries']);
$children = $countries->children()->all();
foreach($children as $child) {
echo $child->name;
}
To get the first level children of a node
$countries = Menu::findOne(['name' => 'Countries']);
$children = $countries->children(1)->all();
foreach($children as $child) {
echo $child->name;
}
Getting parents of a node
To get all the parents of a node
$countries = Menu::findOne(['name' => 'Countries']);
$parents = $countries->parents()->all();
foreach($parents as $parent) {
echo $parent->name;
}
To get the first parent of a node
$countries = Menu::findOne(['name' => 'Countries']);
$parent = $countries->parents(1)->one();
echo $parent->name;