paolzi/yii2-adjacency-list

Yii2 的邻接列表行为

安装次数: 182,296

依赖项: 20

建议者: 0

安全性: 0

星标: 67

关注者: 8

分支: 12

公开问题: 3

类型:yii2-extension

v2.2.0 2018-08-06 07:37 UTC

This package is auto-updated.

Last update: 2024-09-12 22:35:07 UTC


README

在数据库表中存储树结构的邻接列表算法实现。

Packagist Version Code Coverage Build Status Total Downloads

安装

通过 Composer 安装

composer require paulzi/yii2-adjacency-list

或在您的 composer.json 文件的 require 部分添加:

"paulzi/yii2-adjacency-list" : "^2.2"

require

迁移示例

class m150722_150000_adjacency_list 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('{{%adjacency_list}}', [
            'id'        => Schema::TYPE_PK,
            'parent_id' => Schema::TYPE_INTEGER . ' NULL',
            'sort'      => Schema::TYPE_INTEGER . ' NOT NULL',
            'name'      => Schema::TYPE_STRING . ' NOT NULL', // example field
        ], $tableOptions);
        $this->createIndex('parent_sort', '{{%adjacency_list}}', ['parent_id', 'sort']);
    }
}

配置

use paulzi\adjacencyList\AdjacencyListBehavior;

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

可选地,您可以设置查询以查找根节点

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

查询类

use paulzi\adjacencyList\AdjacencyListQueryTrait;

class SampleQuery extends \yii\db\ActiveQuery
{
    use AdjacencyListQueryTrait;
}

可排序行为

此行为附加了 SortableBehavior。您可以使用其方法(例如,reorder())。

选项

  • $parentAttribute = 'parent_id' - 表模式中的父属性。
  • $sortable = [] - SortableBehavior 设置 - 查看 paulzi/yii2-sortable
  • $checkLoop = false - 移动节点时检查循环(较慢)。
  • $parentsJoinLevels = 3 - 查找祖先时的连接级别数量。
  • $childrenJoinLevels = 3 - 查找后代时的连接级别数量。

用法

选择

获取根节点

如果您连接 AdjacencyListQueryTrait,则可以获取所有根节点

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

获取节点的祖先

要获取节点的祖先

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

要获取节点的父节点

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

要获取节点的根节点

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

获取有序主键祖先列表

$node11 = Sample::findOne(['name' => 'node 1.1']);
$ids = $node11->getParentsIds();
$ids = $node11->getParentsIds(3, false); // get 3 levels of ancestors primary keys with force updating from DB 

获取节点的后代

要获取节点的所有后代

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

*注意:保证每个父节点上的顺序,不同父节点的节点可以混合在一起,并且选项 childrenJoinLevels 可以改变此顺序。

为节点及其后代填充 children 关系

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

要获取节点的子节点

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

获取每个级别的有序主键后代数组

$node11 = Sample::findOne(['name' => 'node 1.1']);
$ids = $node11->getDescendantsIds(); // get array of per-level descendants primary keys
$ids = $node11->getDescendantsIds(null, true); // get flat array of descendants primary keys
$ids = $node11->getDescendantsIds(3, false, false); // get 3 levels array of per-level descendants primary keys with force updating from DB 

*注意:保证每个父节点上的顺序,不同父节点的节点可以混合在一起,并且选项 childrenJoinLevels 可以改变此顺序。

获取叶节点

要获取节点的所有叶节点

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

获取相邻节点

要获取下一个节点

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

要获取前一个节点

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

一些检查

$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

修改

要创建根节点

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

注意:如果您允许多个树且未设置属性 tree,则自动采用主键值。

将节点作为另一个节点的第一个子节点添加

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

将节点作为另一个节点的最后一个子节点添加

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

在另一个节点之前插入节点

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

在另一个节点之后插入节点

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

删除具有后代的节点

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

注意:当使用 delete() 删除时,子节点与父节点混合

重新排序子节点

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

从 1.x 升级到 2.x

  1. 将属性 sortAttributestep 移入 sortable 属性。
  2. 将命名空间从 paulzi\adjacencylist 更改为 paulzi\adjacencyList
  3. 包含 paulzi\yii2-sortable(执行 composer update)。