sivanandaperumal / 测试仓库
Laravel 的邻接表闭包表数据库设计模式实现,包括树恢复
dev-master
2019-05-07 06:53 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: 2024-10-03 08:25:22 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 和 实际深度 列
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()的返回值。


