场景
- 无限级分类是经常遇到的设计模式
分析
- 无限级分类常用的模式 (每种模式都是根据需要选择)
- 邻接列表模式
- 物化路径模式
- 闭包表模式
邻接列表模式
- 表结构
- node_id
- parent_id
- name
- 优点
- 操作简单
- 缺点
- 生成一棵树很难
- 适合场景
- 4层结构之内的分类
物化路径模式
- 表结构
- path
- name
- 缺点
- 理论上不能实现真正的无限级别分类,因为path总有长度的限制
- 优点
- 查询后代 祖代 父级 子级 很方便, 很容易生成一棵树适合: 明确知道层级的树, eg: 生物科目, 国家行政区划
- 查询
- 后代
- select * from path_tree where path like "/1/%
- 子代
- select * from path_tree where path regexp “/1/[0-9]*$”
- 祖代
- select * from path_tree where “/1/110000/110100/110101” like concat(path, ‘%’) and path <> “/1/110000/110100/110101”
- 后代
闭包表
-
表结构(需要两张表)
- 节点表
- name
- id
- 关系表
- ancestor_id 祖代ID
- descendant_id 后代ID
- distance 祖代节点到后代节点的距离
- 节点表
-
优点
- 空间换时间 查询时非常快的
- 获取特定$node下的一个树也很简单
- 获取 n o d e 所 有 的 后 代 节 点 的 子 节 点 集 合 node所有的后代节点的子节点集合 node所有的后代节点的子节点集合collection
- 对$collection进行轮询转换操作就可以生成一棵树了
-
查询
- set $collect = 本节点以及节点的后代集合
- 删除:
- 删除祖先ID是$collect
- 删除后代ID是$collect
- 删除节点表中的$collect
- 节点迁移:
- 删除后代ID是 c o l l e c t 的 collect的 collect的node的祖代
- 插入新的后代ID是 c o l l e c t 的 collect的 collect的node新的祖代
- 添加
- 在关系表中添加一条distance=0 的数据
可以某些时候可以帮助更快的一棵树, SELECT * FROM book_closure_relationship where ancestor_id=3;如果没有到本身的节点,还要自己在做下附加
- 如果插入的是全新的没有后代关系的新节点, 则插入新节点与祖代关系
- 如果是在原本的树中插入一个新的层级节点,则重复上一步骤,然后进行节点迁移
- 在关系表中添加一条distance=0 的数据
// 具体的整合过程类似邻接列表模式
$list_permissions = \Ultraware\Roles\Models\Permission::all()->toArray();
$list_permissions = array_column($list_permissions, null, 'id');
$list_container = [];
foreach ($list_permissions as $key => $permission) {
$parent_id = $permission['parent_id'];
// 如果是顶级的话 则不需要寻找父级
if (!$parent_id) {
$list_container[] = &$list_permissions[$key];
continue;
}
// 给对应的父生成子级
$list_permissions[$parent_id]['sons'][] = &$list_permissions[$key];
}
return $list_container;