paolzi / yii2-adjacency-list
Yii2 的邻接列表行为
v2.2.0
2018-08-06 07:37 UTC
Requires
- php: >=5.4.0
- paulzi/yii2-sortable: ~1.0
- yiisoft/yii2: ~2.0.0
Requires (Dev)
- phpunit/dbunit: ~1.0
- phpunit/phpunit: ~4.0
README
在数据库表中存储树结构的邻接列表算法实现。
安装
通过 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
- 将属性
sortAttribute
、step
移入sortable
属性。 - 将命名空间从
paulzi\adjacencylist
更改为paulzi\adjacencyList
。 - 包含
paulzi\yii2-sortable
(执行composer update
)。