A modern nested sets behavior for the Yii framework utilizing the Modified Preorder Tree Traversal algorithm.
The preferred way to install this extension is through composer.
Either run
$ composer require creocoder/yii2-nested-setsor add
"creocoder/yii2-nested-sets": "0.9.*"
to the require section of your composer.json file.
Run the following command
$ yii migrate/create create_menu_tableOpen the /path/to/migrations/m_xxxxxx_xxxxxx_create_menu_table.php file,
inside the up() method add the following
$this->createTable('{{%menu}}', [
    'id' => $this->primaryKey(),
    //'tree' => $this->integer()->notNull(),
    'lft' => $this->integer()->notNull(),
    'rgt' => $this->integer()->notNull(),
    'depth' => $this->integer()->notNull(),
    'name' => $this->string()->notNull(),
]);To use multiple tree mode uncomment tree field.
Configure model as follows
use creocoder\nestedsets\NestedSetsBehavior;
class Menu extends \yii\db\ActiveRecord
{
    public function behaviors() {
        return [
            'tree' => [
                'class' => NestedSetsBehavior::className(),
                // 'treeAttribute' => 'tree',
                // 'leftAttribute' => 'lft',
                // 'rightAttribute' => 'rgt',
                // 'depthAttribute' => 'depth',
            ],
        ];
    }
    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }
    public static function find()
    {
        return new MenuQuery(get_called_class());
    }
}To use multiple tree mode uncomment treeAttribute array key inside behaviors() method.
Configure query class as follows
use creocoder\nestedsets\NestedSetsQueryBehavior;
class MenuQuery extends \yii\db\ActiveQuery
{
    public function behaviors() {
        return [
            NestedSetsQueryBehavior::className(),
        ];
    }
}To make a root node
$countries = new Menu(['name' => 'Countries']);
$countries->makeRoot();The tree will look like this
- Countries
To prepend 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
To append a node as the last child of another node
$australia = new Menu(['name' => 'Australia']);
$australia->appendTo($countries);The tree will look like this
- Countries
    - Russia
    - Australia
To 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
To 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
To get all the root nodes
$roots = Menu::find()->roots()->all();To get all the leaves nodes
$leaves = Menu::find()->leaves()->all();To get all the leaves of a node
$countries = Menu::findOne(['name' => 'Countries']);
$leaves = $countries->leaves()->all();To get all the children of a node
$countries = Menu::findOne(['name' => 'Countries']);
$children = $countries->children()->all();To get the first level children of a node
$countries = Menu::findOne(['name' => 'Countries']);
$children = $countries->children(1)->all();To get all the parents of a node
$countries = Menu::findOne(['name' => 'Countries']);
$parents = $countries->parents()->all();To get the first parent of a node
$countries = Menu::findOne(['name' => 'Countries']);
$parent = $countries->parents(1)->one();Support this project and others by creocoder via gratipay.