分类的话一般用的都是无限极分类,无限极分类的有点是灵活,容易插入,但是在分类量特别大的情况下,使用前序遍历树算法代替无限极分类更好,因为当分类特别多的时候无限极分类的查询是每次都要查询所有,所以前序遍历树算法在此方面的能更好的。当然如果分类涉及经常变更,更改。无限极分类还是有他的有点。在此,分享一个自己的实现类。
<?php /** * 前序遍历树算法实现无限极分类 * @author zaizai * @link http://www.tuhuokeji.com */ class Category { private $tablename = null; public function __construct($tablename) { if(is_null($this->$tablename)){ $this->tablename = $tablename; } } /** * 设置表名 * @Author zaizai * @DateTime 2016-04-02T11:31:39+0800 * @param string $tablename [description] */ public function setTbale(string $tablename) { return $this->tablename = $tablename; } public function getTable() { return $this->tablename; } /** * 显示树状结构 * @Author zaizai * @DateTime 2016-04-02T11:33:33+0800 * @return [type] [description] */ public function view($pageindex,$pagesize,$where = '') { $total = pdo_fetchcolumn('select count(id) from '.tablename($this->tablename).' where id!=1'); $list = pdo_fetchAll('select * from '.tablename($this->tablename).$where.' order by lft asc limit ' . ($pageindex - 1) * $pagesize . ',' . $pagesize); $pager = pagination($total, $pageindex, $pagesize); //两个循环而已,没有递归 $parent = array(); $arr_list = array(); foreach($list as $item){ if(count($parent)){ while (count($parent) -1 > 0 && $parent[count($parent) -1]['rgt'] < $item['rgt']){ array_pop($parent); } } $item['depath'] = count($parent); $parent[] = $item; $arr_list[]= $item; } //显示树状结构 foreach($arr_list as $k=> $a) { if($a['id'] != 1 ){ if($a['depath'] !=1){ $arr_list[$k]['view'] = str_repeat(" ", $a['depath']).'|---'; } }else{ unset($arr_list[$k]); } } return array('list'=>$arr_list,'pager'=>$pager); } /** * 插入操作很简单找到其父节点,之后把左值和右值大于父节点左值的节点的左右值加上2,之后再插入本节点,左右值分别为父节点左值加一和加二 * @Author zaizai * @DateTime 2016-04-02T11:34:01+0800 * @param [type] $parent_id [description] * @param [type] $data [description] */ public function add($parent_id,$data) { $parent_id = empty($parent_id)?1:$parent_id; //获取到父级分类的lft rgt $parent_category = pdo_get($this->tablename,array('id'=>$parent_id),array('lft','rgt','id')); // 1.左值和右值大于父节点左值的节点的左右值加上2 if(!empty($parent_category)){ pdo_query('update '.tablename($this->tablename).' set lft=lft+2 where lft >'.$parent_category['lft']); pdo_query('update '.tablename($this->tablename).' set rgt=rgt+2 where rgt >'.$parent_category['lft']); } $data = array_merge(array('lft'=>$parent_category['lft']+1,'rgt'=>$parent_category['lft']+2),$data); return pdo_insert($this->tablename,$data); } /** * 删除 * * #1.得到删除的节点,将右值减去左值然后加1,得到值$width = $rgt - $lft + 1; * #2.删除左右值之间的所有节点 * #3.修改条件为大于本节点右值的所有节点,操作为把他们的左右值都减去$width * @Author zaizai * @DateTime 2016-04-02T11:36:44+0800 * @param int $id 删除的节点id * @return bool 返回值 */ public function delete($id) { //通过分类id获取分类 $category = pdo_get($this->tablename,array('id'=>$id),array('id','lft','rgt')); //计算$width $width = $category['rgt'] - $category['lft'] + 1; // 1.删除该条分类 $res = pdo_delete($this->tablename,array('id'=>$id)); // 2.删除左右值之间的所有分类 pdo_query('delete from '.tablename($this->tablename).' where lft>:lft and lft<:rgt and id!=1',array(':lft'=>$category['lft'],':rgt'=>$category['rgt'])); // 3.修改其它节点的值 $res1 = pdo_update($this->tablename,array('lft'=>"lft-{$width}"),array('lft'=>$category['rgt'])); $res2 = pdo_update($this->tablename,array('rgt'=>"rgt-{$width}"),array('rgt'=>$category['rgt'])); return $res; } /** * 编辑节点 * @Author zaizai * @DateTime 2016-04-02T11:34:58+0800 * @param int $id 节点名称 * @param array $data 入库的数据 * @return bool 返回值 */ public function edit($id,$data) { //不用说了, 直接通过id编辑 return pdo_update($this->tablename,$data,array('id'=>$id)); } //获取子孙 public function getSons($id) { $item = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$id)); if($item){ $sql = 'SELECT `id`,`title`,`lft`,`rgt` FROM '.tablename($this->tablename).' WHERE `lft`>='.$item['lft'].' AND `rgt`<='.$item['rgt']; return pdo_fetchAll($sql); } return false; } /** * 获取子类的直接父类 * @Author zaizai * @DateTime 2016-05-03T11:00:43+0800 * @param int $sonid 子类的id * @return array|false 直接父类 */ public function getParent($sonid) { $item = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$sonid)); if($item){ $sql = 'SELECT `id`,`title`,`lft`,`rgt` FROM '.tablename($this->tablename).' WHERE `lft`<'.$item['lft'].' AND `rgt`>'.$item['rgt'].' order by rgt asc limit 1'; return pdo_fetch($sql); } return false; } /** * 获取所有的子类 * @Author zaizai * @DateTime 2016-05-03T11:00:05+0800 * @param int $sonid 子类的id * @return array 所有的父类 */ public function getParents($sonid) { $item = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$sonid)); if($item){ $sql = 'SELECT `id`,`title`,`lft`,`rgt` FROM '.tablename($this->tablename).' WHERE `lft`<'.$item['lft'].' AND `rgt`>'.$item['rgt']; return pdo_fetchAll($sql); } return false; } /** * 取出第几级 * @Author zaizai * @DateTime 2016-05-13T18:07:09+0800 * @param [type] $depath 层级 * @return [type] [description] */ public function get_Paret($depath = 1) { $list = pdo_fetchAll('select * from '.tablename($this->tablename) .' where status=:status order by lft asc',array(':status'=>0)); //两个循环而已,没有递归 $parent = array(); $arr_list = array(); foreach($list as $k => $item){ if(count($parent)){ while (count($parent) -1 > 0 && $parent[count($parent) -1]['rgt'] < $item['rgt']){ array_pop($parent); } } $item['depath'] = count($parent); $parent[] = $item; $arr_list[]= $item; if($item['id'] != 1 ){ if($item['depath'] == $depath){ $aa[] = $item; //按照sort排序 foreach ($aa as $key => $row) { $vals[$key] = $row['sort']; } array_multisort($vals, SORT_ASC, $aa); } }else{ unset($list[$k]); } } return $aa; } /** * 取出某父级的第几级子级 * @Author zaizai * @DateTime 2016-05-13T18:07:09+0800 * @param [type] $depath 层级 * @return [type] [description] */ public function get_sons_level($id,$depath = 1) { $abc = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$id)); if($abc){ $list = pdo_fetchAll('select * from '.tablename($this->tablename).' WHERE `lft`>='.$abc['lft'].' AND `rgt`<='.$abc['rgt'] .' order by lft asc'); } //两个循环而已,没有递归 $parent = array(); $arr_list = array(); foreach($list as $k => $item){ if(count($parent)){ while (count($parent) -1 > 0 && $parent[count($parent) -1]['rgt'] < $item['rgt']){ array_pop($parent); } } $item['depath'] = count($parent); $parent[] = $item; $arr_list[]= $item; if($item['id'] != 1 ){ if($item['depath'] == $depath){ $aa[] = $item; //按照sort排序 foreach ($aa as $key => $row) { $vals[$key] = $row['sort']; } array_multisort($vals, SORT_ASC, $aa); } }else{ unset($list[$k]); } } return $aa; } //测试排序 public function test_sort($where=''){ foreach ($this->get_Paret(1) as $v){ //PHP<5.5 用这个 $parentid[]=$v['id']; } for ($i=0;$i<count($parentid);$i++){ $sons[$parentid[$i]]= ($this->get_sons_level($parentid[$i],1)); } foreach ($sons as $k=>$v){ $sons[$parentid[$k]]=$v[$k]; } foreach ($this->get_Paret(1) as $k=>$v){ //PHP<5.5 用这个 $parent[]=$v; } foreach ($this->get_Paret(2) as $v){ //PHP<5.5 用这个 $sonsid[]=$v['id']; } for ($i=0;$i<count($sonsid);$i++){ $sun[$sonsid[$i]]= ($this->get_sons_level($sonsid[$i],1)); } foreach ($sun as $k=>$v){ $sun[$sonsid[$k]]=$v[$k]; } return $this->name($parent,$sons,$sun); } public function name($a,$b,$c) { $list = array(); $list[] = $a; $list[] = $b; $list[] = $c; return $list; } }