PHP 无限级分类数据库设计及实现

背景

  • 最近复习算法,
    在此对无限级分类的实现方法稍作整理,当然也是参考了道友的经验,
    目测适合实际的项目应用,
    当然,也有不少公司的笔试题还会涉及到呢,有何问题,欢迎各位道友指摘 …

操作环境:Win10
使用语言:PHP
使用框架:ThinkPHP 3.2.3

前期准备

  • ①. 首先,实现无限级分类的方式有:
> 1. 以父 ID设计,运用递归实现的方式
> 2. 以全路径实现的无限分类方式
  • ②. 其次,数据表设计思路
- 对应于上述的两种实现方式,那么在数据表设计时也可以有两种方式,参考所给的数据表截图
> 1. 如果采用 父ID方式,
     字段只需使用 "id,pid,cate_name" 的主要三个即可
> 2. 如果采用 全路径方式, 
     字段只需使用 "id,cate_name,path "的主要三个即可,注意:full_path 其实只作参考即可


代码实现

  • 此处,讲解几个核心方法,
    完整代码可根据后面的附录进行下载参考,
    请注意此处提及的核心处理代码都在文件ZmModel.class.php

①. 父 ID 方式

  • 核心处理代码如下,注意参数备注信息,便于正确的调用
 /**
     * 数据库设计 递归方式 获取无限极分类数据 由上到下进行获取
     * @param int $pid      父级ID,默认为根级分类 0
     * @param int $sel_id   所选中的分类ID,多用于前端 selected 标识
     * @param array $result 数组整合
     * @param int $spac     空格间隔,便于前端缩进显示分类所属级别
     * @return array
     */
    public function deepCatesForDown($pid = 0,$sel_id = 0,&$result = [],$spac = 0){
        //空格数目
        $spac += 2;
        //从数据表中获取 父级ID为所需 pid 的全部数据
        $cateList = $this->db_cate
            ->where("pid = $pid")
            ->select();
        //TODO 进行遍历处理
        foreach ($cateList as $key => $value){
            //判断 selected 属性
            if ($sel_id == $value['id']){
                $selectedStr = "selected";
            }else{
                $selectedStr = "";
            }
            $cateList[$key]['cate_name'] = str_repeat('  ',$spac)
                .'|--'.$cateList[$key]['cate_name'] ;
            $cateList[$key]['selected'] = $selectedStr;
            $result[] = $cateList[$key];
            //TODO 此处进行了递归操作
            $this->deepCatesForDown($value['id'],$sel_id,$result,$spac);
        }
        return $result;
    }
  • 控制器调用参考:
$zmModel = new ZmModel();
$cateListDown = $zmModel->deepCatesForDown(0,6);
$this->assign('cateListDown',$cateListDown);
$this->display();
  • 前端 Html 数据显示参考:
<h4>递归方式获取 无限级分类数据</h4>
<select>
    <volist name="cateListDown" id="vo">
        <option {$vo.selected}>{$vo.cate_name}</option>
    </volist>
</select>

②. 全路径实现方式

  • 对应参考上面的介绍方式,核心处理代码如下
 /**
     * 全路径方式 获取无限极分类数据 由上到下进行获取
     * @return array
     */
    public function deepCatesFullPathForDown(){
        //注意排序方式 自动按要求进行排列
        $cateList = $this->db_cate
            ->field("id,cate_name,path,concat(path,',',id) full_path")
            ->order('full_path asc')
            ->select();
        $result = [];
        //遍历数据 方法同上
        foreach ($cateList as $key => $value){
            $deep = explode(',',trim($value['full_path'],','));
            $cateList[$key]['cate_name'] = str_repeat('&nbsp;&nbsp;',count($deep))
                ."|--".$cateList[$key]['cate_name'];
            $result[] = $cateList[$key];
        }
        return $result;
    }
  • 调用及前端显示代码参考同上

实现效果

  • 上述的参考代码,只做了下拉框的实现参考,对于全链接方式的实现可直接参考源代码
    在这里插入图片描述

附录

源代码下载 >>>

补充信息 (2021-02-27)

  • 毕竟本篇文章已历史悠远
    在鄙人的开发过程中,感觉代码方式发生了很大改变,在此做点补充信息!

  • 以分类数据表设计为例:

第一种,代码实现

  • 这种方式,是先获取所有的分类数据,然后经过递归方法处理
    最终得到一个多维数组
    缺点:如果数据量庞大,操作会很慢(普遍递归都是这个缺点!)
/**
     * 递归获取,全部树状分类数据
     * @param array $arr 分类数组
     * @param int $pid 父ID
     * @return array
     */
    public function tree($arr = [], $pid = 0){
        $list = [];
        foreach ($arr as $key=> $val){
            if ($val['parent_id'] == $pid){
                //把这个节点从数组中移除,减少后续递归消耗
                unset($arr[$key]);
                //开始递归,查找父ID为该节点ID的节点,级别则为原级别+1
                $child = $this->tree($arr,$val['cat_id']);
                if ($child){
                    $val['child'] = $child;
                }
                $list[] = $val;
            }
        }
        return $list;
    }
	     /**
	     * 测试接口
	     */
        public function test(){
	        $map = [['status', '=', 1]];
	        $res = Db::name('xcategorys')
	            ->field('cat_id,cat_name,parent_id')
	            ->where($map)
	            ->order(["list_order"=>"asc","cat_id"=>'asc'])
	            ->select();
	        $result = $this->tree($res,0);
	        var_dump($result);
    }
  • 最终获取的分类数组数据展示如下:
    在这里插入图片描述

第二种,代码实现

  • 对比上面的方式
    是在递归方法中,获取数据库数据

    实现上来讲比较好理解,但是不适合集成通用的方法,毕竟每个表字段都会有所出入的!

    /**
     * 集成 待选商品分类数据
     * @param int $level
     * @param int $parent_id
     * @return array
     */
    public function getCmsToSelCategoryList($level = 1,$parent_id = 0)
    {
        $map = [['level', '=', $level],['status', '=', 1]];
        $map[] = ['parent_id', '=', $parent_id];

        $res = $this
            ->field('cat_id,cat_name')
            ->where($map)
            ->order(["list_order"=>"asc","cat_id"=>'asc'])
            ->select();

        foreach ($res as $key => $value){
            $childRes = $this->getCmsToSelCategoryList(intval($level+1),intval($value['cat_id']));
            $res[$key]['children'] = $childRes;
        }
        return isset($res) ? $res->toArray() : [];
    }
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值