用户
 找回密码
 入住 CI 中国社区
搜索
查看: 7850|回复: 4
收起左侧

根据parent_id递归的无限分类和下拉菜单。

[复制链接]
发表于 2008-4-13 10:02:33 | 显示全部楼层 |阅读模式
先说下,这个对小树来讲还是很快的,大树没有测试,呵呵,递归对大树没什么优势。
数据库设计
id, title, parent_id, last
[int,char(255),int,bool]
MODEL:
先来个正常全部列表哦:
PHP复制代码
 
  function get_list()
  {
    $query = $this->db->get('catalog');
    return $query->result_array();
  }
 
复制代码

在看一个根据parent_id自动生成的多维数组:
PHP复制代码
 function get_tree($parent_id = null)
{
$this->db->where('parent_id',$parent_id);
$this->db->select('id,parent_id,last,title_english');
$query = $this->db->get('catalog');
$list['son'] = $query->result_array();
foreach ($list['son'] as &$row) {
if(array_key_exists('last',$row))
{
if(!$row['last'])
{
$temp = $this->get_tree($row['id']);//这里用了个递归
$row['son'] = $temp['son'];
}
}
 
 
}
return $list;
}
复制代码

下一个是生成视图的下拉列表或者多级的菜单:
PHP复制代码
 
function read_tree($tree,$display = array(
  'str_out'=>array('open'=>"<ul>\n",'close'=>"</ul>\n"),
  'str_in'=> array('open'=>"<li>",'close'=>"</li>\n"),
  'blank'=>array('many'=>0,'what'=>' ','increase'=>0),
  'attr'=>array('value'=>'id'),
  'with_last' => true)
  )
  {
    $str = "";
    $str .= $display['str_out']['open'];
    foreach ($tree['son'] as $t)
    {
      if(array_key_exists('last',$t))
      {
        $show = true;
        if($t['last']){if(!$display['with_last']){$show = false;}}
        if($show){
          $str .= $display['str_in']['open'];
          if($display['attr'] != array())
          {
            $str = substr($str,0,strlen($str)-1);
            foreach ($display['attr'] as $k=>$v)
            {
              $str .= ' '.$k.'="'.$t[$v].'"';
            }
            $str .= '>';
          }
          for($i=0;$i<$display['blank']['many'];$i++)
          {
            $str .= $display['blank']['what'];
          }
          $str .= $t['title_english'].$display['str_in']['close'];
        }
      }
      if(array_key_exists('son',$t))
      {
        //    print_r($display);
        $str .= $this->read_tree(
        $t,
        array('str_out'=>$display['str_out'],
        'str_in'=>$display['str_in'],
        'blank'=>array(
        'many'=>($display['blank']['many']+$display['blank']['increase']),
        'what'=>$display['blank']['what'],
        'increase'=>$display['blank']['increase']
        ),
        'attr' => $display['attr'],
        'with_last'=>$display['with_last'],
        )
        );
      }
    }
    $str .= $display['str_out']['close'];
    return $str;
  }
 
复制代码

控制器里调用:
PHP复制代码
 
 $tree = $this->catalog_model->get_tree();
    echo '<select>';
    echo $this->catalog_model->read_tree($tree,array('str_out'=>array('open'=>'','close'=>''),'str_in'=>array('open'=>'<option>','close'=>'</option>'),'blank'=>array('increase'=>1,'what'=>'    ','many'=>0),'attr'=>array('value'=>'id'),'with_last'=>false));
    echo '</select>';
 
复制代码

大家把echo的东西换成变量传递到视图里就可以啦。
参数设置的有点多,但是还是很好用D。
嘿嘿。数据结构学的不好,搞了半个下午。
希望能帮助更多的人。

评分

参与人数 1威望 +5 收起 理由
Hex + 5 原创内容

查看全部评分

发表于 2008-9-18 19:33:33 | 显示全部楼层
兄弟,将实例打个包吧。。
发表于 2009-10-23 10:13:17 | 显示全部楼层
我最担心的就是每次递归就要查一遍数据库,当数据库有1万条数据,你的栏目有50个,那就相当于要递归50次(就是循环50次),查询50次数据库,总数就要查询50万行得出结果。如果是多人cms系统,这种查询方法就很吓人了。

我认为最好的方法是把符合要求的 50条数据先查出来放在一个数组里。然后对数组进行递归或者别的什么方法进行计算。

就和楼主说的,只能使用小树。

有没有高人指点一下大树的递归啊
发表于 2009-10-27 17:14:15 | 显示全部楼层
本帖最后由 pk4321 于 2009-10-27 17:30 编辑

ptCID        ptPID        ptName        ptRank
1        0        A        0001
3        1        A1        00010001
6        3        A11        000100010001
5        1        A2        00010002
4        1        A3        00010003
2        0        B        0002

至少加个类似上面的最后一列,就完全避免了递归了,但就是添加、移动、删除结点的需要额外的维护!
这样一来,这个树的每个子树最多可以有9999个结点,而整个树的深度 varchar(200) 就有50级!

CI应该增加一个用以上模式的树的一个library
发表于 2012-11-20 14:30:01 | 显示全部楼层
分类当然要做成缓存文件,考虑性能的话

本版积分规则