PHP带节点操作的无限分类实现方法详解
author:一佰互联 2019-04-26   click:147

本文实例讲述了PHP带节点操作的无限分类实现方法。分享给大家供大家参考,具体如下:

包含(移动多个节点;移动单个节点;删除多个节点;删除单个节点;新增节点),另附数据库表结构

一、db sql语句

//db used for php无限分类
create table tree(
  id int(10) not null primary key auto_increment,
  name varchar(255) not null,
  lft int(10) not null default 0,
  rgt int(10) not null default 0,
  status int(1) not null default 0,
  index lft (`lft`),
  index rgt (`rgt`),
  index status(`status`)
)charset utf8;
insert into tree value (null,"Food",1,18,0);
insert into tree value (null,"Fruit",2,11,0);
insert into tree value (null,"Red",3,6,0);
insert into tree value (null,"Cherry",4,5,0);
insert into tree value (null,"Yellow",7,10,0);
insert into tree value (null,"Banana",8,9,0);
insert into tree value (null,"Meat",12,17,0);
insert into tree value (null,"Beef",13,14,0);
insert into tree value (null,"Pork",15,16,0);

二、php文件

<?php
error_reporting(0);
/*
             1 Food 18
      +------------------------------+
    2 Fruit 11           12 Meat 17
  +-------------+         +------------+
3 Red 6   7 Yellow 10    13 Beef 14  15 Pork 16
4 Cherry 5  8 Banana 9
descendants = (right – left - 1) / 2
*/
/**
 *用于移动一个节点(包括子节点)
 *@param array $pdata = array("id"=>主键,"root"=>名称) 二选一 父节点(为空时插入最大的父节点)
 *@param array $ndata = array("id"=>主键,"root"=>名称) 二选一 下一个兄弟节点(没有兄弟的时候就不用)
 *@param array $cdata = array("id"=>主键,"root"=>名称) 二选一 当前待移动的节点
 */
function move_tree_all($pdata=array(),$ndata=array(),$cdata=array()) {
  $cid  = $cdata["id"] ? intval($cdata["id"]) : "";
  $croot = $cdata["root"];
  if(!$cid && !$croot) return;
  //需自加判断
  //1、cdata不能为顶级
  //2、cdata不能比$pdata等级高
  $adata = get_tree_all($cdata); //获取当前移动节点的所有节点
  delete_tree_all($cdata,1); //逻辑删除当前移动节点的所有节点
  foreach($adata as $k => $val) {
    if($k != 0) {
      $pdata = array("root"=>$val["parent"]);
      insert_tree($pdata,"",$val["name"],1);
    } else { //first
      insert_tree($pdata,$ndata,$val["name"],1);
    }
  }
}
/**
 *用于移动一个节点(不包括子节点)
 *@param array $pdata = array("id"=>主键,"root"=>名称) 二选一 父节点(为空时插入最大的父节点)
 *@param array $ndata = array("id"=>主键,"root"=>名称) 二选一 下一个兄弟节点(没有兄弟的时候就不用)
 *@param array $cdata = array("id"=>主键,"root"=>名称) 二选一 当前待移动的节点
 */
function move_tree_item($pdata=array(),$ndata=array(),$cdata=array()) {
  $cid  = $cdata["id"] ? intval($cdata["id"]) : "";
  $croot = $cdata["root"];
  if(!$cid && !$croot) return;
  //需自加判断
  //1、cdata不能为顶级
  if(!$croot) {
    $sql = "SELECT name from tree where id = $cid";
    $result = mysql_query($sql);
    $row = mysql_fetch_assoc($result);
    $croot = $row["name"];
    unset($sql);
  }
  delete_tree_item($cdata,1);
  insert_tree($pdata,$ndata,$croot,1);
}
/**
 *用于插入一个节点
 *@param array $pdata = array("id"=>主键,"root"=>名称) 二选一 父节点(为空时插入最大的父节点)
 *@param array $ndata = array("id"=>主键,"root"=>名称) 二选一 下一个兄弟节点(没有兄弟的时候就不用)
 *@param string $name string 新插入的名称
 *@param int $update 默认为空,为1时更新插入
 */
function insert_tree($pdata=array(),$ndata=array(),$name,$update="") {
  if(!$name) return;
  $pid  = $pdata["id"] ? intval($pdata["id"]) : "";
  $proot = $pdata["root"];
  $nid  = $ndata["id"] ? intval($ndata["id"]) : "";
  $nroot = $ndata["root"];
  //有父无兄(最小的子节点,父节点的最后一个儿子)
  if(($pid || $proot) && !($nid || $nroot)) {
    $sql  = $pid ? "SELECT lft, rgt FROM tree WHERE id = "{$pid}";" : "SELECT lft, rgt FROM tree WHERE name = "{$proot}";";
    $result = mysql_query($sql);
    $row  = mysql_fetch_assoc($result);
    unset($sql);
    //新节点
    $lft = $row["rgt"];
    $rgt = $lft+1;
    if(!$update) {
      $sql = "insert into tree values (null,"{$name}",$lft,$rgt,0);";
      $sql1 = "update tree set rgt = rgt+2 where rgt >= {$row["rgt"]}";
      $sql2 = "update tree set lft = lft+2 where lft >= {$row["rgt"]}";
    } else {
      $sql = "update tree set lft=$lft,rgt=$rgt,status=0 where name ="{$name}";";
      $sql1 = "update tree set rgt = rgt+2 where status =0 and rgt >= {$row["rgt"]}";
      $sql2 = "update tree set lft = lft+2 where status =0 and lft >= {$row["rgt"]}";
    }
    mysql_query($sql1);
    mysql_query($sql2);
    mysql_query($sql); //last add new data
  }
  //有父有兄
  if(($pid || $proot) && ($nid || $nroot)) {
    $sql  = $nid ? "SELECT lft, rgt FROM tree WHERE id = "{$nid}";" : "SELECT lft, rgt FROM tree WHERE name = "{$nroot}";";
    $result = mysql_query($sql);
    $row  = mysql_fetch_assoc($result);
    unset($sql);
    //新节点
    $lft = $row["lft"];
    $rgt = $lft+1;
    if(!$update) {
      $sql = "insert into tree values (null,"{$name}",$lft,$rgt,0);";
      $sql1 = "update tree set rgt = rgt+2 where rgt >= {$row["lft"]};";
      $sql2 = "update tree set lft = lft+2 where lft >= {$row["lft"]};";
    } else {
      $sql = "update tree set lft=$lft,rgt=$rgt,status=0 where name ="{$name}";";
      $sql1 = "update tree set rgt = rgt+2 where status = 0 and rgt >= {$row["lft"]};";
      $sql2 = "update tree set lft = lft+2 where status = 0 and lft >= {$row["lft"]};";
    }
    mysql_query($sql1);
    mysql_query($sql2);
    mysql_query($sql); //last add new data
  }
  //无父无兄(大佬)
  if(!($pid || $proot) && !($nid || $nroot)) {
    $sql  = "SELECT max(`rgt`) as rgt FROM tree;";
    $result = mysql_query($sql);
    $row  = mysql_fetch_assoc($result);
    unset($sql);
    //新节点
    $lft = 1;
    $rgt = $row["rgt"]+2;
    if(!$update) {
      $sql = "insert into tree values (null,"{$name}",$lft,$rgt,0);";
      $sql1 = "update tree set rgt = rgt+1";
      $sql2 = "update tree set lft = lft+1";
    } else {
      $sql = "update tree set lft=$lft,rgt=$rgt,status=0 where name ="{$name}";";
      $sql1 = "update tree set rgt = rgt+1 where status = 0";
      $sql2 = "update tree set lft = lft+1 where status = 0";
    }
    mysql_query($sql1);
    mysql_query($sql2);
    mysql_query($sql); //last add new data
  }
}
/**
 *用于删除一个节点(包括子节点)
 *@param array $data = array("id"=>主键,"root"=>名称) 二选一
 *@param int $update 默认为空,为1时逻辑删除
 */
function delete_tree_all($data,$update="") {
  $id  = $data["id"] ? intval($data["id"]) : "";
  $root = $data["root"];
  if(!$id && !$root) return;
  $sql  = $id ? "SELECT lft, rgt FROM tree WHERE id = "{$id}";" : "SELECT lft, rgt FROM tree WHERE name = "{$root}";";
  $result = mysql_query($sql);
  $row  = mysql_fetch_assoc($result);
  unset($sql);
  $middle = $row["rgt"]-$row["lft"]+1;
  if(!$update) {
    $sql  = "delete from tree where lft BETWEEN "" . $row["lft"] . "" AND "" . $row["rgt"] .""";
    $sql1  = "update tree set rgt = rgt-{$middle} where rgt > {$row["rgt"]}";
    $sql2  = "update tree set lft = lft-{$middle} where lft > {$row["rgt"]}";
  } else {
    $sql  = "update tree set status = 1 where lft BETWEEN "" . $row["lft"] . "" AND "" . $row["rgt"] .""";
    $sql1  = "update tree set rgt = rgt-{$middle} where status=0 and rgt > {$row["rgt"]}";
    $sql2  = "update tree set lft = lft-{$middle} where status=0 and lft > {$row["rgt"]}";
  }
  mysql_query($sql);
  mysql_query($sql1);
  mysql_query($sql2);
}
/**
 *用于删除一个节点(不包括子节点)
 *@param array $data = array("id"=>主键,"root"=>名称) 二选一
 *@param int $update 默认为空,为1时逻辑删除
 */
function delete_tree_item($data,$update="") {
  $id  = $data["id"] ? intval($data["id"]) : "";
  $root = $data["root"];
  if(!$id && !$root) return;
  $sql  = $id ? "SELECT id,lft, rgt FROM tree WHERE id = "{$id}";" : "SELECT id,lft, rgt FROM tree WHERE name = "{$root}";";
  $result = mysql_query($sql);
  $row  = mysql_fetch_assoc($result);
  unset($sql);
  if(!$update) {
    $sql = "delete from tree where id = {$row["id"]};";
    $sql1 = "update tree set rgt = rgt-1,lft = lft -1 where lft > {$row["lft"]} and rgt < {$row["rgt"]}";
    $sql2 = "update tree set lft = lft-2 where lft > {$row["rgt"]}";
    $sql3 = "update tree set rgt = rgt-2 where rgt > {$row["rgt"]}";
  } else {
    $sql = "update tree set status = 1 where id = {$row["id"]};";
    $sql1 = "update tree set rgt = rgt-1,lft = lft -1 where status = 0 and lft > {$row["lft"]} and rgt < {$row["rgt"]}";
    $sql2 = "update tree set lft = lft-2 where status = 0 and lft > {$row["rgt"]}";
    $sql3 = "update tree set rgt = rgt-2 where status = 0 and rgt > {$row["rgt"]}";
  }
  mysql_query($sql);
  mysql_query($sql1);
  //can do or not do just right,but not do load empty 2 number in middle
  mysql_query($sql2);
  mysql_query($sql3);
}
/**
 *用于获取所有的节点
 *@param array $data = array("id"=>主键,"root"=>名称) 二选一
 */
function get_tree_all($data) {
  $id  = $data["id"] ? intval($data["id"]) : "";
  $root = $data["root"];
  if(!$id && !$root) return;
  $sql  = $id ? "SELECT lft, rgt FROM tree WHERE id = "{$id}";" : "SELECT lft, rgt FROM tree WHERE name = "{$root}";";
  $result = mysql_query($sql);
  $row  = mysql_fetch_assoc($result);
  $adata = array(); //所有数据
  $right = array(); //计数
  $prev  = array();
  $result = mysql_query("SELECT id,name, lft, rgt FROM tree WHERE lft BETWEEN "" . $row["lft"] . "" AND "" . $row["rgt"] ."" ORDER BY lft ASC ;");
  while ($row = mysql_fetch_assoc($result)) {
    if (count($right) > 0) {
      while ($right[count($right) - 1] < $row["rgt"]) { // 检查我们是否应该将节点移出堆栈
        array_pop($right);
        array_pop($prev);
      }
    }
    $parent = $prev ? end($prev) : "";
    $adata[] = array("id"=>$row["id"],"name"=>$row["name"],"level"=>count($right),"parent"=>$parent);
    $right[] = $row["rgt"];
    $prev[] = $row["name"];
  }
  return $adata;
}
/**
 *用于展示分类
 *@param array $data = array("id"=>主键,"root"=>名称) 二选一
 */
function display_tree($data) {
  $id  = $data["id"] ? intval($data["id"]) : "";
  $root = $data["root"];
  if(!$id && !$root) return;
  $sql  = $id ? "SELECT lft, rgt FROM tree WHERE id = "{$id}";" : "SELECT lft, rgt FROM tree WHERE name = "{$root}";";
  $result = mysql_query($sql);
  $row  = mysql_fetch_assoc($result);
  $right = array();
  $result = mysql_query("SELECT name, lft, rgt FROM tree WHERE lft BETWEEN "" . $row["lft"] . "" AND "" . $row["rgt"] ."" ORDER BY lft ASC ;");
  while ($row = mysql_fetch_assoc($result)) {
    if (count($right) > 0) { // 检查我们是否应该将节点移出堆栈
      while ($right[count($right) - 1] < $row["rgt"]) {
        array_pop($right);
      }
    }
    echo str_repeat(" ",count($right)) . $row["name"] . "
";
    $right[] = $row["rgt"];
  }
}
mysql_connect("localhost","root","") or die("connect error");
mysql_select_db("test") or die("database error");
mysql_query("set names utf8");
display_tree(array("root"=>"Food"));
//display_tree(array("root"=>"bigboss"));
//move_tree_all($pdata=array("root"=>"Fruit"),$ndata=array("root"=>"Red"),$cdata=array("root"=>"Meat"));
//move_tree_all("","",$cdata=array("root"=>"Meat"));
//move_tree_item("","",array("root"=>"Red"));
//move_tree_item(array("root"=>"Red"),array("root"=>"Cherry"),array("root"=>"Fruit"));
//delete_tree_all(array("root"=>"Yellow"));
//delete_tree_all(array("root"=>"Meat"));
//delete_tree_item(array("root"=>"Meat"));
//insert_tree("","","bigboss");
//insert_tree(array("root"=>"Red"),"","dalao");
//insert_tree(array("root"=>"Red"),array("root"=>"Cherry"),"baddalao");
//insert_tree(array("root"=>"Fruit"),array("root"=>"Red"),"Redbother");
display_tree(array("root"=>"Food"));

更多关于PHP相关内容感兴趣的读者可查看本站专题:《php字符串(string)用法总结》、《PHP数组(Array)操作技巧大全》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《php面向对象程序设计入门教程》、《PHP网络编程技巧总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

希望本文所述对大家PHP程序设计有所帮助。