soda-framework / eloquent-closure
此包已被废弃,不再维护。没有建议替代包。
Laravel 的邻接列表闭包表数据库设计模式实现
0.2.1
2017-05-09 06:33 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 not auto-updated.
Last update: 2022-03-15 05:55:15 UTC
README
分支
- L4 支持 Laravel 4
- L5.1 支持 Laravel < 5.2
- 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()
的返回值。