上篇博客里面说了一下无限分类,其中用国民级算法递归和巧妙引用来取值的方法都有,然后抱着对无限分类感兴趣的心理,上网学习发现还有左右值大法,因为本人不是计算机专业的,所以觉得这种方法非常的好玩,一番研究之后,分享一下这个左右值大法。
上一篇博客中,有这样的一个分类,这个分类众所周知是通过PID方式来实现内部分类逻辑的
同样的几条数据,我们换一种方式,这次引入左右值
初看之下感觉非常的紊乱,来细细的捋一下,跟着左右值走一下
从1开始:
后台首页(1)→数据一览(2,3)→更新日志(4,5)→添加日志(6,7)→后台首页(8)
看出问题来了吗?凡是在1-8中间的左右值,都是属于这个分类的子分类,明白了这其中的关系,接下来再进一步的利用这种神奇的左右值进行操作
$sql = "select * from sp_auth_bak order by auth_left"
结合左右值的特性可以很容易的通过这样一条简单的sql指令获取到已经排好序的分类数组,仅仅一次查询操作而已,左右值的魅力初步体现,不再需要后期的递归,不需要任何多余的操作,只需要按照左值顺序排序,一定是排序好的结果
这个也是很简单的,比如我们要找到后台首页的所有后代分类,首先取得它的左右值分别是1,8,那么则有,查找左右值在这个范围内的数据就行,
select * from sp_auth_bak where auth_left between 1 and 8 order by auth_left
是不是非常的简单粗暴,真是省去了很多后期处理数据的烦恼
这个其实也很简单,它的父级分类,必定同时满足两个条件,左值小于待查找分类的左值,右值则是大于,sql就不写了
通常的思路是利用count,这里其实很简单的通过(右值-左值-1)/2就可以得到数量,为什么呢?
前面看来,查找数据确实很方便,但是如果需要插入一条数据呢,举个例子,我们在“添加日志<6,7>” 下面添加一个新的分类叫做 “添加更新日志”
现在来分析一下,需要什么操作
$sql = "update sp_auth_bak set auth_left = auth_left + 2 where auth_left >=7 ";
$sql = "update sp_auth_bak set auth_right = auth_right + 2 where auth_right >=7 ";
经过这一步操作后,现在的表结构应该是这样的
4. 万事俱备,接下来将<8,9>插入,完美收工
$sql = "insert into sp_auth_bak value(null,'添加更新日志',7,8,2)";//最后一个2是为了前台处理缩进的时候有个依据,这里的2是等于父分类的level值加1
接下来,只要查找左值在1-10之间的数据就能得到后台首页的所有后代分类了,在读取数据上,依然还是一条简单的sql就可以搞定了
如何根据左右值来修改呢,这里,其实可以看出来某些问题了,这也是左右值一个尴尬的地方,不过话说回来,在这里的话,个人的解决办法是两步走
从上面可以看出来,虽然左右值在读取数据方面具有很大的优势,但是如果需要频繁的增删改,实际左右值的操作步骤还是挺多的,在这里有一个解决办法,将左右值加减2的操作放在一些框架的钩子函数或者mysql的触发器里面,在执行增删改的时候自动调用这种操作
可以看到,如果需要频繁的增删改,用PID的方式依然是很简便的,而如果需要频繁的读取大批量的分类数据,因为左右值没有递归操作,所以效率很高。
下面引入一个函数,将已有的PID表结构更新为左右值结构,在现有的表结构上增加左右值字段之后,执行函数。实际操作起来,需要修改里面的一些参数,或者自己再进行进一步的封装,这里是使用PDO做的操作
/**将父子结构变成左右值结构的函数 数据库相关的参数例如表名字段自己修改
** @param int $pid 顶级分类的父ID
** @param int $left 从哪个左值开始排列,最终结果起始左值会等于$left+1,因为无论如何都会递归1次
** @param pdo $dbh 一个pdo资源,如果在tp框架,可以是一个model
*/
function getTree($pid,$left,$dbh)
{
$right = $left + 1;
$result = $dbh->query("
SELECT auth_id
FROM sp_auth_copy
WHERE auth_pid = '" . $pid . "'
;"
);
foreach ($result as $row) {
var_dump($row["auth_id"]);
$right = getTree($row['auth_id'], $right,$dbh);
}
$dbh->exec("
UPDATE sp_auth_copy
SET
lft = '" . $left . "',
rgt= '" . $right . "'
WHERE auth_id = '" . $pid . "'
;"
);
return $right+1;
}
有了这种函数之后,可以有巧妙的办法,那就是执行增删改的时候,用PID的方式执行,而在增删改之后,调用这个函数,更新左右值,而前台等地方需要读取分类的时候,就使用左右值,当然,函数的调用依然是可以放在触发器或者钩子函数里面的