1
0
Fork 0
mirror of https://github.com/Oreolek/yii2-nested-sets.git synced 2024-05-16 15:58:17 +03:00
Go to file
Alexander Kochetov f63b4691e7 Merge pull request #51 from antness/mysql_test_fix
Fixed parent class for MysqlNestedSetsQueryBehaviorTest
2015-01-19 17:42:49 +03:00
src Added NestedSetsBehavior::leaves feature 2015-01-08 23:28:33 +03:00
tests Fixed parent class for MysqlNestedSetsQueryBehaviorTest 2015-01-19 12:14:55 +03:00
.gitignore Updated .gitignore 2015-01-02 20:21:37 +03:00
.scrutinizer.yml Added .scrutinizer.yml 2015-01-02 21:08:10 +03:00
.travis.yml Updated .travis.yml 2015-01-15 04:46:48 +03:00
composer.json Moved source files to "src" directory, configure phpunit coverage settings 2015-01-04 13:51:58 +03:00
composer.lock Updated composer.lock 2015-01-15 04:38:03 +03:00
LICENSE.md Updated LICENSE.md 2015-01-02 07:22:45 +03:00
phpunit.xml.dist Moved source files to "src" directory, configure phpunit coverage settings 2015-01-04 13:51:58 +03:00
README.md Updated README.md 2015-01-16 23:41:17 +03:00

Nested Sets Behavior for Yii 2

PayPal Donate Build Status Code Coverage

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:

  1. lft, type integer. If you do not want to use this default name you can change it by setting up the leftAttribute attribute. The example assumes that you want to change the name to left

    public function behaviors() {
        return [
            'nestedSets' => [
                'class' => NestedSetsBehavior::className(),
                'leftAttribute' => 'left',
            ],
        ];
    }
    
  2. rgt, type integer. To change the name of the field make the same setting as for lft, but use the attribute rightAttribute

  3. depth, type integer. To change the name of the field make the same setting as for lft, but use the attribute depthAttribute

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;