serj / sortable-tree
一组类,用于为Yii2创建和维护树结构。
v1.0.1
2019-04-20 11:50 UTC
Requires
- php: >=7.0
- serj/sortable: ~1.2.0
- yiisoft/yii2: ~2.0.6
Requires (Dev)
- codeception/codeception: ^2.5
This package is auto-updated.
Last update: 2024-09-28 14:48:04 UTC
README
一组类,用于为Yii2创建和维护类似树的结构。
安装
要将组件导入您的项目,将以下行添加到您的composer.json文件的require部分
"serj/sortable-tree": "~1.0.0"
或者运行以下命令
$ composer require serj/sortable-tree "~1.0.0"
要创建数据库表,应用迁移。
./yii migrate --migrationPath=@app/vendor/serj/sortable-tree/migrations
用法
添加根节点
Tree::addItem();
添加嵌套项
假设根项的id = 1。要在根节点下添加项
Tree::addItem(1);
让我们再添加一个项,但插入到上一个项之前。我们假设最后一个插入的项的id = 2。
$parent = 1; $target = 2; $position = 'before'; Tree::addItem($parent, $target, $position);
目前,我们的树看起来是这样的
├── 1
│ ├── 3
│ └── 2
移动项
让我们交换项2和3
$parent = 1; // we move items under the same parent $id = 3 // move this item $target = 2; // we want to locate the item after this one $position = 'after'; Tree::moveTo($id, $parent, $target, $position)
现在它应该像这样
├── 1
│ ├── 2
│ └── 3
让我们将项3嵌套到项2中
$parent = 2; $id = 3 $position = 'after'; Tree::moveTo($id, $parent)
结果是
├── 1
│ ├── 2
│ ├── 3
删除
Tree::deleteRecursive(2);
我们删除了项2及其子项3。只剩下根项。
├── 1
获取树
Tree::getDescendingTree();
还有许多其他方法可以操作树。有关更多信息,您可以探索Tree类的公共方法和单元测试。
我想存储更多信息
假设您想存储title、created_at、updated_at字段。并且您不再想从树中删除项,而是将其标记为deleted。为了实现这一点,我们可以扩展Tree类。但是首先,让我们修改迁移。
class m171217_033811_sortable_tree_tables extends Migration { /** * @inheritdoc */ public function safeUp() { $this->createTable('{{%tree_data}}', [ 'id' => $this->primaryKey(), 'parent_id' => $this->integer(), 'level' => $this->integer(), 'sort' => $this->integer(), 'title' => $this->string(), 'deleted' => $this->boolean()->defaultValue(false), 'created_at' => $this->timestamp()->defaultValue('NOW()'), 'updated_at' => $this->timestamp()->defaultValue('NOW()'), 'deleted_at' => $this->timestamp(), ]); $this->createTable('{{%tree_structure}}', [ 'id' => $this->primaryKey(), 'parent' => $this->integer(), 'child' => $this->integer() ]); } /** * @inheritdoc */ public function safeDown() { $this->dropTable('{{%tree_data}}'); $this->dropTable('{{%tree_structure}}'); } }
不要忘记应用新的迁移。
扩展树类。添加和覆盖一些方法。
<?php use yii\db\Expression; class TreeExtended extends \serj\sortableTree\Tree { /** * @inheritdoc */ public static function instantiate($row) { $model = new self(); $model->setFilter(new Filter()); return $model; } /** * @inheritdoc */ public function rules() { return array_merge( parent::rules(), [ ['title', 'string'], ['deleted', 'boolean'], [['created_at', 'updated_at', 'deleted_at'], 'safe'] ] ); } /** * @param int $id * @return null|RecordTreeData|\yii\db\ActiveRecord * @throws NotFoundHttpException */ public function editTitle(int $id, $title) { $model = self::getRecord($id); $model->setAttributes([ 'title' => $title, 'updated_at' => new Expression('NOW()') ]); if ($model->save()) { $model->refresh(); return $model; } return $model; } /** * @param array $ids * @return int * @throws \yii\db\Exception */ protected static function deleteItems(array $ids) { return \Yii::$app->db->createCommand() ->update( self::tableName(), ['deleted' => true, 'deleted_at' => new Expression('NOW()')], ['id' => $ids] ) ->execute(); } }
为了跳过已删除的项,我们在类构造函数中添加了一个过滤器。让我们实现它。
<?php use yii\db\Query; class Filter implements \serj\sortableTree\FilterInterface { /** * @inheritdoc */ public function applyFilter(Query $query) { $query->andWhere([ 'deleted' => false ]); return $query; } }
现在要添加一个项,传递一个包含额外属性的数组,这些属性已添加到迁移中。在我们的例子中是title。
TreeExtended::addItem(0, null, null , ['title' => 'Root']);
要编辑现有项的标题
TreeExtended::editTitle(1, 'Root modified');
使用与上面相同的方法进行删除。
Tree::deleteRecursive(1);
树类触发一系列事件,这可能很有用。
const EVENT_AFTER_ADD = 'tree.after_add'; const EVENT_BEFORE_MOVE = 'tree.before_move'; const EVENT_AFTER_MOVE = 'tree.after_move'; const EVENT_BEFORE_DELETE = 'tree.before_delete'; const EVENT_AFTER_DELETE = 'tree.after_delete'; const EVENT_BEFORE_TREE_QUERY = 'tree.before_tree_query';
例如,在删除项之前获取项的ID
\Yii::$app->on(Tree::EVENT_BEFORE_DELETE, function (\serj\sortableTree\EventTree $event) { print_r($event->senderData['ids']); });
使用MySQL数据库(默认为PostgreSQL)
Tree::setSortManager( new Sortable([ 'targetTable' => Tree::tableName(), 'pkColumn' => 'id', 'srtColumn' => 'sort', 'grpColumn' => 'parent_id', 'databaseDriver' => Sortable::DB_DRIVER_MYSQL ]) );