前一周写的吧,使用中效果还不错。

 主要思想来自:http://www.phpobject.net/blog/read.php?49[url=http://www.phpobject.net/blog/read.php?49][/url]

  这里就不多解释原理了,直接发代码。

  PS:这里代码是不能直接使用的,必须结合我的一些其他库类。应该说思想才是最重要的,这里主要提供一种分类的思路。


<?
/**
-- 
-- 表的结构 `daxue8_category`
-- 

CREATE TABLE `daxue8_category` (
  `cid` smallint(6) NOT NULL auto_increment,
  `pid` smallint(6) NOT NULL default '0',
  `level` smallint(6) NOT NULL default '0',
  `cname` char(64) NOT NULL default '',
  `lft` smallint(6) NOT NULL default '0',
  `rgt` smallint(6) NOT NULL default '0',
  `uid` mediumint(8) NOT NULL default '0',
  `username` char(32) NOT NULL default '',
  `ctime` int(10) NOT NULL default '0',
  `cstate` tinyint(1) NOT NULL default '0',
  `gnum` mediumint(8) NOT NULL default '0',
  `orderstyle` smallint(3) NOT NULL default '0',
  PRIMARY KEY  (`cid`)
) TYPE=MyISAM AUTO_INCREMENT=2 ;

-- 
-- 导出表中的数据 `daxue8_category`
-- 

INSERT INTO `daxue8_category` VALUES (1, 0, 1, 'root', 1, 2, 0, '管理员', 1163608814, 1, 0, 0);
*/
class category
{
    var 
$module;
    
    var 
$tbname;
    
    function 
category()
    {
        
$this->tbname=TB_PREX.'_category';
        
$this->module=new module($this->tbname);
    }
    
    
/**
      * 增加子节点
      * @param array $node 待增加子节点的属性
      * @param int $pid 父节点的ID
    */
    
function add($node,$pid){
        
//检查是否已经存在该节点
        
if($node_exist=$this->module->detail('where pid='.$pid.' and cname=\''.$node['cname'].'\'')){
            
//$this->error(__FUNCTION__.'():该节点'.$node['cname'].'已经存在!');
            //print_r($node_exist);
            
return $node_exist['cid'];
        }
        
//获取父节点信息
        
$pnode=$this->get_by_cid($pid);
        
//更新其他节点
        
$this->module->query('update `'.$this->tbname.'` set lft=lft+2 where lft>'.$pnode['rgt']);
        
$this->module->query('update `'.$this->tbname.'` set rgt=rgt+2 where rgt>='.$pnode['rgt']);
        
//插入新节点
        
$node['pid']=$pid;
        
$node['lft']=$pnode['rgt'];
        
$node['rgt']=$pnode['rgt']+1;
        
$node['level']=$pnode['level']+1;//层次加一
        
return $this->module->add($node);
    }
    
    
/**
      * 删除节点
      * @param $cid 待删除的节点的ID
      * @param $delete_childern 如果该节点存在子节点,是否强制删除。设置未true,则当存在子节点的时候,删除失败,返回false
      *
    */
    
function delete($cid,$delete_childern=false)
    {
        
//获取节点信息
        
$node=$this->get_by_cid($cid);
        if((
$this->child_num($node)>0)&&(!$delete_childern))$this->error(__FUNCTION__.'():该节点存在子节点!');
        
//删除该节点及其所有子节点
        
$this->module->delete('where lft between '.$node['lft'].' and '.$node['rgt']);
        
//修改相应的左右键值
        
$plus=$node['rgt']-$node['lft']+1;
        
$this->module->query('update `'.$this->tbname.'` set lft=lft-'.$plus.' where lft>'.$node['rgt']);
        
$this->module->query('update `'.$this->tbname.'` set rgt=rgt-'.$plus.' where rgt>'.$node['rgt']);
        return 
true;
    }
    
    
/**
      * 更新一个节点
      * @param array $set更新集
      * @param int $cid 更新的节点的主键ID
    */
    
function update($set,$cid){
        return 
$this->module->update($set,'where cid='.$cid);
    }
    
    
/**
      * 选取节点及其子节点
      * @param int $cid节点的主键ID
      * @param int $deep选取深度
    */
    
function select($cid,$deep=0)
    {
        
//获取节点信息
        
$node=$this->get_by_cid($cid);
        
$where='where lft between '.$node['lft'].' and '.$node['rgt'];
        if(!empty(
$deep))$where.=' and level<'.$node['level']+$deep;
        if(
$deep==1){
            
$where.=' order by orderstyle desc';
        }else{
            
$where.=' order by lft asc';            
        }
        return 
$this->module->select($where);
    }
    
    
/**
      * 获取父节点路径
      * @param int $cid 节点的ID 
    */
    
function get_parent($cid)
    {
        
$node=$this->get_by_cid($cid);
        return 
$this->module->select('where lft<='.$node['lft'].' and rgt>='.$node['rgt'].' order by lft asc');
    }
    
/**
      * 选取子节点
      * @param int $cid节点的主键ID
      * @param int $deep选取深度
    */
    
function get_children($pid,$deep=0){
        
//获取节点信息
        
$pnode=$this->get_by_cid($pid);
        
$where='where lft>'.$pnode['lft'].' and rgt<'.$pnode['rgt'];
        if(!empty(
$deep))$where.=' and level<='.($pnode['level']+$deep);
        if(
$deep==1){
            
$where.=' order by orderstyle desc';
        }else{
            
$where.=' order by lft asc';            
        }
        return 
$this->module->select($where);
    }
    
    
/**
      * 获取第deep层子节点
      * @param int $cid节点的主键ID
      * @param int $deep选取深度
    */
    
function get_level_children($pid,$deep){
        
//获取节点信息
        
$pnode=$this->get_by_cid($pid);
        
$where='where lft>'.$pnode['lft'].' and rgt<'.$pnode['rgt'];
        
$where.=' and level='.($pnode['level']+$deep);
        
$where.=' order by orderstyle desc';
        return 
$this->module->select($where);
    }
    
    
/**
      * 获取节点信息
      * @param $cid 节点的主键ID
      * @return array $node
    */
    
function get_by_cid($cid){
        
$node=$this->module->detail('where cid='.$cid);
        if(!
$node)$this->error(__FUNCTION__.'():获取节点'.$cid.'失败!');
        return 
$node;
    }
    
/**
      * 获取子节点的数目
      * @param array $node 节点信息
      * @return num
    */
    
function child_num($node){
        return (
$node['rgt']-$node['lft']-1)/2;
    }
    
/**
      * 按照层次显示分类
      * @param int $cid节点的主键ID
      * @output
    */
    
function display($cid)
    {
        
$nodes=$this->select($cid);
        foreach(
$nodes as $node){
            echo 
str_repeat('   ',$node['level']-1).$node['cname']."\n";
        }
    }
/*-------private-----------------------------------*/
    
    
function error($msg){
        die(
'ERROR : file '.__FILE__.' function '.$msg);
    }
}
?>
评论(5) | 引用(825) | 阅读(6831)
chouyou Says:
2008/06/28 23:46
整个的我已经实现了,移动分支,思路也有了,就是设一个加锁标志,对需要移动分支加锁,移动后解锁,关于根,我是预插入一个记录做跟,问题是:我移动分支的时候需要个选择把所有的节点列出来,如果有太多节点,我怎么显示它好呢?
gouki Says:
2007/10/25 10:48
一直没有搞清楚,你如何移动节点?还是不移动???移动一下节点要考虑的事情太多太多太多了……
52php Says:
2007/06/08 07:32
最近在做一个系统正需要无限分类,不过一直都没找到比较合意的类,看了mysql官方的文档和你的类打算借用你的类,不过感觉你的这个类好像蛮多不完善的,比如 function add($node,$pid){ ……} 这个函数缺少$pid的判断,当第一次添加的时候不可能有$pid

另外 $this->module=new module($this->tbname);  这边的module类没贴出来,也没说明。我只是猜测应该是个数据库操作类。

不过总的来说思路是搞清楚了。这里并没有批评什么的意思,只是交流下,同时谢谢你哦!
Yimin Says: Homepage
2006/12/21 21:20
实际运用中我也是这么用。 呵呵。
呵呵,我是不同项目不一样。有时候也保存节点路径
feifengxlq 回复于 2006/12/21 21:27
Yimin Says: Email Homepage
2006/12/16 20:42
Nested Set:
http://liyimin.net/blog/?p=97
嗯,思想是这样的。呵呵,增加了一些层次,这样方便点
feifengxlq 回复于 2006/12/18 12:43
分页: 1/83 第一页 1 2 3 4 5 6 7 8 9 10 下页 最后页
发表评论
昵称 [注册]
密码 游客无需密码
网址
电邮
打开HTML 打开UBB 打开表情 隐藏 记住我