byteasc / closure-table
基于邻接列表的闭包表数据库设计模式实现,用于Laravel。包括树的恢复
8.0.2
2020-09-10 18:13 UTC
Requires
- php: >=5.4.0
Requires (Dev)
- doctrine/dbal: dev-master
- mockery/mockery: dev-master
- orchestra/testbench: dev-master
- phpunit/phpunit: dev-master
- way/laravel-test-helpers: dev-master
- way/phpunit-wrappers: dev-master
This package is auto-updated.
Last update: 2024-09-07 02:03:29 UTC
README
分支
- L4 支持 Laravel 4
- L5.1 支持 Laravel < 5.2
- L5.3 支持 Laravel 5.2-5.3
- L5.4 支持 Laravel 5.4
- master 适用于任何实际的 Laravel 版本,所以请小心
嗨,这是一个 Laravel 的数据库包。当你需要在数据库中操作层次数据时使用。该包是实现一种名为闭包表的知名数据库设计模式的实现。该包包括模型和迁移生成器。
安装
要安装该包,请在 composer.json 中添加以下内容
"require": { "franzose/closure-table": "4.*" }
并更新到 app/config/app.php
'providers' => array( // ... 'Franzose\ClosureTable\ClosureTableServiceProvider', ),
设置你的 ClosureTable
创建模型和迁移
例如,假设你正在处理页面。你可以使用 artisan
命令自动创建模型和迁移,而无需手动准备所有内容。打开终端并输入以下内容
php artisan closuretable:make --entity=page
命令的所有选项
--namespace
,-ns
(可选):类命名空间,由--entity
和--closure
选项设置,有助于避免这些选项中的命名空间重复--entity
,-e
:实体类名;如果使用了命名空间名称,则默认的闭包类名称将加上该命名空间--entity-table
,-et
(可选):实体表名--closure
,-c
(可选):闭包类名--closure-table
(可选),-ct
:闭包表名--models-path
,-mdl
(可选):自定义模型路径--migrations-path
,-mgr
(可选):自定义迁移路径--use-innodb
和-i
(可选):新参数使 InnoDB 迁移也成为可选。设置此选项将启用 InnoDB 引擎。
这就是大部分内容,朋友们!刚刚为你创建了“虚拟”的内容。你需要在实体迁移中添加一些字段,因为创建的“虚拟”内容只包括id
、parent_id
、position
和real depth
这四个必需
列
id
是一个常规的自增列parent_id
列用于简化直接祖先查询,例如,简化整个树的构建position
列被广泛用于该包,以使实体可排序real depth
列也用于简化查询并减少其数量
默认情况下,实体的闭包表包括以下列
- 自增标识符
- 祖先列 指向父节点
- 后代列 指向子节点
- 深度列 显示树中节点的深度
这是闭包表模式设计的一部分,所以请记住,你绝对不能删除这四个列。
请记住,许多事情都可以自定义,所以请查看“自定义”以获取更多信息。
编码时间
一旦创建了你的模型及其数据库表,最后,你就可以开始实际编码了。这里我将向您展示 ClosureTable 的特定方法。
直接祖先(父节点)
$parent = Page::find(15)->getParent();
祖先
$page = Page::find(15); $ancestors = $page->getAncestors(); $ancestors = $page->getAncestorsTree(); // Tree structure $ancestors = $page->getAncestorsWhere('position', '=', 1); $hasAncestors = $page->hasAncestors(); $ancestorsNumber = $page->countAncestors();
直接后代(子节点)
$page = Page::find(15); $children = $page->getChildren(); $hasChildren = $page->hasChildren(); $childrenNumber = $page->countChildren(); $newChild = new Page(array( 'title' => 'The title', 'excerpt' => 'The excerpt', 'content' => 'The content of a child' )); $newChild2 = new Page(array( 'title' => 'The title', 'excerpt' => 'The excerpt', 'content' => 'The content of a child' )); $page->addChild($newChild); //you can set child position $page->addChild($newChild, 5); //you can get the child $child = $page->addChild($newChild, null, true); $page->addChildren([$newChild, $newChild2]); $page->getChildAt(5); $page->getFirstChild(); $page->getLastChild(); $page->getChildrenRange(0, 2); $page->removeChild(0); $page->removeChild(0, true); //force delete $page->removeChildren(0, 3); $page->removeChildren(0, 3, true); //force delete
后代
$page = Page::find(15); $descendants = $page->getDescendants(); $descendants = $page->getDescendantsWhere('position', '=', 1); $descendantsTree = $page->getDescendantsTree(); $hasDescendants = $page->hasDescendants(); $descendantsNumber = $page->countDescendants();
兄弟
$page = Page::find(15); $first = $page->getFirstSibling(); //or $page->getSiblingAt(0); $last = $page->getLastSibling(); $atpos = $page->getSiblingAt(5); $prevOne = $page->getPrevSibling(); $prevAll = $page->getPrevSiblings(); $hasPrevs = $page->hasPrevSiblings(); $prevsNumber = $page->countPrevSiblings(); $nextOne = $page->getNextSibling(); $nextAll = $page->getNextSiblings(); $hasNext = $page->hasNextSiblings(); $nextNumber = $page->countNextSiblings(); //in both directions $hasSiblings = $page->hasSiblings(); $siblingsNumber = $page->countSiblings(); $sibligns = $page->getSiblingsRange(0, 2); $page->addSibling(new Page); $page->addSibling(new Page, 3); //third position //add and get the sibling $sibling = $page->addSibling(new Page, null, true); $page->addSiblings([new Page, new Page]); $page->addSiblings([new Page, new Page], 5); //insert from fifth position
根(没有祖先的实体)
$roots = Page::getRoots(); $isRoot = Page::find(23)->isRoot(); Page::find(11)->makeRoot(0); //at the moment we always have to set a position when making node a root
整个树
$tree = Page::getTree(); $treeByCondition = Page::getTreeWhere('position', '>=', 1);
您处理集合,因此您可以像通常一样控制其项。子项?它们已经加载。
$tree = Page::getTree(); $page = $tree->find(15); $children = $page->getChildren(); $child = $page->getChildAt(3); $grandchildren = $page->getChildAt(3)->getChildren(); //and so on
移动
$page = Page::find(25); $page->moveTo(0, Page::find(14)); $page->moveTo(0, 14);
删除子树
如果由于某种原因您不使用外键,您可以手动删除子树。这将删除页面及其所有子项
$page = Page::find(34); $page->deleteSubtree(); $page->deleteSubtree(true); //with subtree ancestor $page->deleteSubtree(false, true); //without subtree ancestor and force delete
自定义
您可以使用ClosureTable artisan
命令创建的自定义类来自定义默认项
- 实体表名:更改
protected $table
属性 - 闭包表名:在您的
ClosureTable
(例如PageClosure
)中进行相同的更改 - 实体的
parent_id
、position
和real depth
列名:分别更改getParentIdColumn()
、getPositionColumn()
和getRealDepthColumn()
的返回值 - 闭包表的
ancestor
、descendant
和depth
列名:分别更改getAncestorColumn()
、getDescendantColumn()
和getDepthColumn()
的返回值。