嵌套模型中的节点移动
嵌套模型中的节点移动
嵌套模型:http://www.cnblogs.com/ac1985482/p/Managing-Hierarchical-Data-in-MySQL.html
此文中详细的描述了嵌套模型中的各种查询,对于层级结构,可以用一条sql语句就能将它查询出来。
使用最多的就是查目录,比如查询id为10的所有父级节点
select a.* from node a,node b where a.lft <b.lft and a.rgt >b.lft and b.id=10;
这种情况的查询,在嵌套模型的文章中已经说明的非常详细了。我这里主要是写嵌套节点移动的操作。嵌套节点的移动需要把一个节点和子节点看成一个整体的移动。主要思路如下:
假设将id为m的节点移动的节点n的后面
-
将$n后面的位置扩大 $step= m.rgt -m.lft +1 的空间o。
-
将对m执行sql,移动到n的后面,并记录 LFT=m.lft RGT=m.rgt
-
移除空出来的空间
我的使用环境前端使用了一个ztree的js插件,在onDrop事件中反馈了移动的位置。一下为PHP的代码:
代码
// 查找targeNode
$targeQuery=$this->db->query("select * from category_edit_node where id=$targeNode");
$targeNode=$targeQuery->row();
if (!$targeQuery)
return false;
//查找$node 的步长
$query=$this->db->query("select rgt-lft a from category_edit_node where id=$node");
$row=$query->row();
if (!$row)
return false;
$step=$row->a+1;//move node 需要的占用的宽度
//1.将目标位置扩大step的大小 ,这里的type为与targeNode相对的节点
// $type "inner":成为子节点,"prev":成为同级前一个节点,"next":成为同级后一个节点
$targe=0;
if ($type=="inner"){
$targe=$targeNode->lft;
}
if($type=="prev"){
$targe=$targeNode->lft-1;
}
if ($type=="next"){
$targe=$targeNode->rgt;
}
//开始事务
$this->db->trans_start();
//将需要移动到的位置空出来。
$this->db->query("update category_edit_node set lft=lft +$step where lft>$targe and fid=$id");
$this->db->query("update category_edit_node set rgt=rgt+$step where rgt>$targe and fid=$id");
//获取扩大后的node
$query=$this->db->query("select rgt,depth from category_edit_node where id=$node ");
$row=$query->row();
$rgt=$row->rgt;
if ($type=="inner"){
$depth=$targeNode->depth+1;
}else{
$depth=$targeNode->depth;
}
//2. 将node节点和子节点的lft rgt修改到扩大的区间
$this->db->query(" update category_edit_node a,category_edit_node b
set a.lft=a.lft-b.lft+$targe+1,a.rgt=a.rgt-b.lft+$targe+1,a.depth=a.depth-b.depth+$depth
where a.fid=$id and b.fid=$id and a.lft >=b.lft and a.lft <b.rgt and b.id=$node;");
//3. 收缩空出来的位置
$this->db->query("update category_edit_node set lft =lft-$step where lft >$rgt and fid=$id");
$this->db->query("update category_edit_node set rgt =rgt -$step where rgt >$rgt and fid=$id");
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
return false;
}else{
return true;
}