PHPackages                             paulzi/yii2-materialized-path - 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. paulzi/yii2-materialized-path

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

paulzi/yii2-materialized-path
=============================

Materialized Path Behavior for Yii2

v2.1.2(1y ago)2619.6k↓70.6%75MITPHPPHP &gt;=5.4.0

Since Aug 28Pushed 1y ago3 watchersCompare

[ Source](https://github.com/paulzi/yii2-materialized-path)[ Packagist](https://packagist.org/packages/paulzi/yii2-materialized-path)[ RSS](/packages/paulzi-yii2-materialized-path/feed)WikiDiscussions master Synced yesterday

READMEChangelogDependencies (4)Versions (16)Used By (5)

Yii2 Materialized Path Behavior
===============================

[](#yii2-materialized-path-behavior)

Implementation of materialized path algorithm for storing the trees in DB tables.

[![Packagist Version](https://camo.githubusercontent.com/935ea634e5110b7de3fc6b886e2bcfe05f976ea2e9b9b3eb7d3b7f0d6f047bdb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7061756c7a692f796969322d6d6174657269616c697a65642d706174682e737667)](https://packagist.org/packages/paulzi/yii2-materialized-path)[![Code Coverage](https://camo.githubusercontent.com/0950566789705a4b675ca30cc6e6b2e18a081a455463cbf3f0fd33bcc7469501/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f636f7665726167652f672f7061756c7a692f796969322d6d6174657269616c697a65642d706174682f6d61737465722e737667)](https://scrutinizer-ci.com/g/paulzi/yii2-materialized-path/?branch=master)[![Build Status](https://camo.githubusercontent.com/f5337d729155d94752f1983458c4e4fb16977978de7c88f8931c5aaff5e19fa8/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f7061756c7a692f796969322d6d6174657269616c697a65642d706174682f6d61737465722e737667)](https://travis-ci.org/paulzi/yii2-materialized-path)[![Total Downloads](https://camo.githubusercontent.com/dd2906c81a9c61a0cc10260db62066240431154a4b086c2e377a9e0a8af40089/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7061756c7a692f796969322d6d6174657269616c697a65642d706174682e737667)](https://packagist.org/packages/paulzi/yii2-materialized-path)

Install
-------

[](#install)

Install via Composer:

```
composer require paulzi/yii2-materialized-path
```

or add

```
"paulzi/yii2-materialized-path" : "^2.1"
```

to the `require` section of your `composer.json` file.

Migrations example
------------------

[](#migrations-example)

Single tree migration:

```
class m150828_150000_single_tree extends Migration
{
    public function up()
    {
        $tableOptions = null;
        if ($this->db->driverName === 'mysql') {
            // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
            $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
        }
        $this->createTable('{{%single_tree}}', [
            'id'    => Schema::TYPE_PK,
            'path'  => Schema::TYPE_STRING . ' NULL',
            'depth' => Schema::TYPE_INTEGER . ' NOT NULL',
            'sort'  => Schema::TYPE_INTEGER . ' NOT NULL',
            'name'  => Schema::TYPE_STRING . ' NOT NULL', // example field
        ], $tableOptions);
        $this->createIndex('path', '{{%single_tree}}', ['path']);
    }
}
```

Multiple tree migration:

```
class m150828_150100_multiple_tree extends Migration
{
    public function up()
    {
        $tableOptions = null;
        if ($this->db->driverName === 'mysql') {
            // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
            $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
        }
        $this->createTable('{{%multiple_tree}}', [
            'id'    => Schema::TYPE_PK,
            'tree'  => Schema::TYPE_INTEGER . ' NULL',
            'path'  => Schema::TYPE_STRING . ' NULL',
            'depth' => Schema::TYPE_INTEGER . ' NOT NULL',
            'sort'  => Schema::TYPE_INTEGER . ' NOT NULL',
            'name'  => Schema::TYPE_STRING . ' NOT NULL', // example field
        ], $tableOptions);
        $this->createIndex('path', '{{%multiple_tree}}', ['tree', 'path']);
    }
}
```

Configuring
-----------

[](#configuring)

```
use paulzi\materializedPath\MaterializedPathBehavior;

class Sample extends \yii\db\ActiveRecord
{
    public function behaviors() {
        return [
            [
                'class' => MaterializedPathBehavior::className(),
                // 'treeAttribute' => 'tree',
            ],
        ];
    }

    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }
}
```

Optional you can setup Query for finding roots:

```
class Sample extends \yii\db\ActiveRecord
{
    public static function find()
    {
        return new SampleQuery(get_called_class());
    }
}
```

Query class:

```
use paulzi\materializedPath\MaterializedPathQueryTrait;

class SampleQuery extends \yii\db\ActiveQuery
{
    use MaterializedPathQueryTrait;
}
```

Sortable Behavior
-----------------

[](#sortable-behavior)

This behavior attach SortableBehavior. You can use its methods (for example, reorder()).

Options
-------

[](#options)

- `$pathAttribute = 'path'` - setup path attribute in table schema.
- `$depthAttribute = 'depth'` - setup depth attribute in table schema.
- `$itemAttribute = null` - setup item attribute in table schema for get path path, if the value is not set - using the primary key.
- `$treeAttribute = null` - setup tree attribute for multiple tree, when item attribute is not primary key.
- `$sortable = []` - SortableBehavior settings - see [paulzi/yii2-sortable](https://github.com/paulzi/yii2-sortable).
- `$delimiter = '/'` - delimiter of path items.
- `$rootDepthValue = 0` - setup value of `$depthAttribute` for root nodes.

Usage
-----

[](#usage)

### Selection

[](#selection)

**Getting the root nodes**

If you connect `MaterializedPathQueryTrait`, you can get all the root nodes:

```
$roots = Sample::find()->roots()->all();
```

**Getting ancestors of a node**

To get ancestors of a node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$parents = $node11->parents; // via relation
$parents = $node11->getParents()->all(); // via query
$parents = $node11->getParents(2)->all(); // get 2 levels of ancestors
```

To get parent of a node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$parent = $node11->parent; // via relation
$parent = $node11->getParent()->one(); // via query
```

To get root of a node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$root = $node11->root; // via relation
$root = $node11->getRoot()->one(); // via query
```

**Getting descendants of a node**

To get all the descendants of a node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$descendants = $node11->descendants; // via relation
$descendants = $node11->getDescendants()->all(); // via query
$descendants = $node11->getDescendants(2, true)->all(); // get 2 levels of descendants and self node
```

To populate `children` relations for self and descendants of a node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$tree = $node11->populateTree(); // populate all levels
$tree = $node11->populateTree(2); // populate 2 levels of descendants
```

To get the children of a node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$children = $node11->children; // via relation
$children = $node11->getChildren()->all(); // via query
```

**Getting the leaves nodes**

To get all the leaves of a node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$leaves = $node11->leaves; // via relation
$leaves = $node11->getLeaves(2)->all(); // get 2 levels of leaves via query
```

**Getting the neighbors nodes**

To get the next node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$next = $node11->next; // via relation
$next = $node11->getNext()->one(); // via query
```

To get the previous node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$prev = $node11->prev; // via relation
$prev = $node11->getPrev()->one(); // via query
```

### Some checks

[](#some-checks)

```
$node1 = Sample::findOne(['name' => 'node 1']);
$node11 = Sample::findOne(['name' => 'node 1.1']);
$node11->isRoot() - return true, if node is root
$node11->isLeaf() - return true, if node is leaf
$node11->isChildOf($node1) - return true, if node11 is child of $node1
```

### Modifications

[](#modifications)

To make a root node:

```
$node11 = new Sample();
$node11->name = 'node 1.1';
$node11->makeRoot()->save();
```

*Note: if you allow multiple trees and attribute `tree` is not set, it automatically takes the primary key value.*

To prepend a node as the first child of another node:

```
$node1 = Sample::findOne(['name' => 'node 1']);
$node11 = new Sample();
$node11->name = 'node 1.1';
$node11->prependTo($node1)->save(); // inserting new node
```

To append a node as the last child of another node:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$node12 = Sample::findOne(['name' => 'node 1.2']);
$node12->appendTo($node11)->save(); // move existing node
```

To insert a node before another node:

```
$node13 = Sample::findOne(['name' => 'node 1.3']);
$node12 = new Sample();
$node12->name = 'node 1.2';
$node12->insertBefore($node13)->save(); // inserting new node
```

To insert a node after another node:

```
$node13 = Sample::findOne(['name' => 'node 1.3']);
$node14 = Sample::findOne(['name' => 'node 1.4']);
$node14->insertAfter($node13)->save(); // move existing node
```

To delete a node with descendants:

```
$node11 = Sample::findOne(['name' => 'node 1.1']);
$node11->delete(); // delete node, children come up to the parent
$node11->deleteWithChildren(); // delete node and all descendants
```

Reorder children:

```
$model = Sample::findOne(1);
$model->reorderChildren(true); // reorder with center zero
$model = Sample::findOne(2);
$model->reorderChildren(false); // reorder from zero
```

Updating from 1.x to 2.x
------------------------

[](#updating-from-1x-to-2x)

1. Move attributes `sortAttribute`, `step` into `sortable` attribute.
2. Change namespace from `paulzi\materializedpath` to `paulzi\materializedPath`.
3. Include `paulzi\yii2-sortable` (`composer update`).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance34

Infrequent updates — may be unmaintained

Popularity36

Limited adoption so far

Community22

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

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

Every ~238 days

Recently: every ~730 days

Total

15

Last Release

628d ago

Major Versions

v1.0.2 → v2.0.02015-12-11

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/9402208?v=4)[PaulZi](/maintainers/PaulZi)[@paulzi](https://github.com/paulzi)

---

Top Contributors

[![paulzi](https://avatars.githubusercontent.com/u/9402208?v=4)](https://github.com/paulzi "paulzi (40 commits)")[![HaruAtari](https://avatars.githubusercontent.com/u/3523420?v=4)](https://github.com/HaruAtari "HaruAtari (10 commits)")[![arogachev](https://avatars.githubusercontent.com/u/8326201?v=4)](https://github.com/arogachev "arogachev (5 commits)")

---

Tags

yii2materialized path

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/paulzi-yii2-materialized-path/health.svg)

```
[![Health](https://phpackages.com/badges/paulzi-yii2-materialized-path/health.svg)](https://phpackages.com/packages/paulzi-yii2-materialized-path)
```

###  Alternatives

[craftcms/cms

Craft CMS

3.6k3.6M3.1k](/packages/craftcms-cms)[paulzi/yii2-adjacency-list

Adjacency List Behavior for Yii2

68248.4k17](/packages/paulzi-yii2-adjacency-list)[paulzi/yii2-auto-tree

Allow apply multiple tree behavior for ActiveRecord in Yii2

5055.7k7](/packages/paulzi-yii2-auto-tree)

PHPackages © 2026

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