大家好,,我是军哥,英文名:JayJun,一直想跟大伙交流一下学习和使用CI的心得和经验,最近也在用CI写一个在线书城项目,已经完成80%,其中有用到无限分类,关于无限分类,有许多的实现方式,今个呢,军哥,跟大家先分享自己写的无限分类类库,只适合CI框架哟,当然你也可以修改后使用到其它地方,接着我们会在CI框架中应用一下(详见附件中代码示例)。这里要求你有一定的面向对象基础,当然了解和熟悉CI(或其它PHP框架)就更好啦。
另外,军哥在代码中应用了市面上热门的一个前端UI框架――bootstarp,这个框架在为我们实现页面样式方面是表现的相当给力!详见:bootstrap前端UI框架中文版官网。
好了,不废话啦,军哥语文学滴不好(小学没少挨老师打手掌心呀),就直接上代码啦!
有学习和研究CI的,欢迎拍砖!!! 代码示例 CI_cate.rar 1、先看效果,有图有真相;
分类显示页:
添加分类页:
编辑分类页:
2、控制器(源码在 application/controllers 文件夹);
- //无限分类控制器功能
- class cate extends CI_Controller
- {
- private $_cate_url = 'cate/'; //无限分类视图路径
- public function __construct()
- {
- parent::__construct();
- $this->base_url = $this->config->item("base_url");
- $this->load->library('category');
- }
- //显示分类
- public function index()
- {
- $data['base_url'] = $this->base_url;
- $data['tree_str'] = $this->category->getListStr();
- $this->load->view($this->_cate_url.'cate_index',$data);
- }
- //编辑分类
- public function edit($cid = '')
- {
- $data['base_url'] = $this->base_url;
- if ($cid != '')
- {
- $query = $data['post'] = $this->category->fetchOne($cid);
- $pid = $query['fatherId'];
- $data['option_str'] = $this->category->getOptionStr(0,true,0,false,$pid);
- }
- else
- {
- $data['option_str'] = $this->category->getOptionStr(0,true,0,false,0);
- }
- $this->load->view($this->_cate_url.'cate_edit',$data);
- }
- //执行插入分类操作
- public function insert()
- {
- //获取表单提交的信息
- $fatherId = $this->input->post('fatherId');
- $cateName = $this->input->post('cateName');
- $content = $this->input->post('content');
- $sort = $this->input->post('sort');
- $display = $this->input->post('display');
- if ($this->category->addCategory($fatherId,$cateName,$content,$sort,$display) > 0)
- {
- echo "<script language=\"javascript\">alert('添加成功!')</script>";
- }
- else
- {
- echo "<script language=\"javascript\">alert('添加失败!')</script>";
- }
- echo "<script language=\"javascript\">history.go(-1);</script>";
- }
- //执行编辑操作
- function update($cid = '')
- {
- $cid = ($cid === '') ? $this->input->post('cid') : $cid;
- if ($cid !== '')
- {
- //获取表单提交的信息
- $fatherId = $this->input->post('fatherId');
- $cateName = $this->input->post('cateName');
- $content = $this->input->post('content');
- $sort = $this->input->post('sort');
- $display = $this->input->post('display');
- if ($this->category->editCategory($cid,$fatherId,$cateName,$content,$sort,$display) > 0)
- {
- echo "<script language=\"javascript\">alert('更新成功!')</script>";
- }
- else
- {
- echo "<script language=\"javascript\">alert('更新失败!')</script>";
- }
- }
- echo "<script language=\"javascript\">history.go(-1);</script>";
- }
- //执行删除操作
- function delete($cid = '')
- {
- if ($cid !== '')
- {
- if ($this->category->delCategory($cid) > 0)
- {
- echo "<script language=\"javascript\">alert('删除成功!')</script>";
- }
- else
- {
- echo "<script language=\"javascript\">alert('删除失败!')</script>";
- }
- }
- echo "<script language=\"javascript\">history.go(-1);</script>";
- }
- }
3、无限分类类库(源码在 application/libraries 文件夹);
/*==================================================================*/
- /* 文件名:Category.php */
- /* 功能:实现无限分类的增删改查,用于codeigniter框架,
- 也可以修改后用于其它用途。 */
- /* 作者:张礼军
- /* 英文名:JayJun QQ:413920268 */
- /* 创建时间:2012-08-29 */
- /* 最后修改时间:2012-08-31 */
- /* copyright (c)2012 jayjun0805@sina.com */
- /*==================================================================*/
- if (!defined('BASEPATH')) exit('No direct script access allowed');
- class Category {
- private $CI; //CI对象
- private $tableName; //要操作的表名
- //表的七个字段
- private $cid; //分类ID
- private $fatherId; //父分类ID
- private $cateName; //分类名称
- private $sort; //分类排序,在同一父级下有多级时,用于排序
- private $content; //分类介绍
- private $level; //分类等级,即当前目录的级别
- private $display; //分类显示状态
- //所取分类的深度
- private $depth = 0;
- private $startLevel = 0;
- /**
- * 构造函数
- * @param $arr 参数包括表名,及分类表的七个字段名,如果没有定义,则采用默认,
- * 默认值
- * 表名:category
- * 分类ID:cid
- * 父ID:fatherId
- * 分类名称:cateName
- * 分类排序:sort
- * 分类介绍:content
- * 分类等级:level
- * 分类显示状态:display
- */
- public function __construct($arr = array())
- {
- //通过引用的方式赋给变量来初始化原始的CodeIgniter对象
- $this->CI = &get_instance();
- //初始化表参数
- $this->tableName = (isset($arr['tableName'])) ? $arr['tableName'] : 'category';
- $this->cid = (isset($arr['cid'])) ? $arr['cid'] : 'cid';
- $this->fatherId = (isset($arr['fatherId'])) ? $arr['fatherId'] : 'fatherId';
- $this->cateName = (isset($arr['cateName'])) ? $arr['cateName'] : 'cateName';
- $this->sort = (isset($arr['sort'])) ? $arr['sort'] : 'sort';
- $this->content = (isset($arr['content'])) ? $arr['content'] : 'content';
- $this->level = (isset($arr['level'])) ? $arr['level'] : 'level';
- $this->display = (isset($arr['display'])) ? $arr['display'] : 'display';
- }
- /**
- * 从数据库取所有分类数据,返回数组
- */
- public function fetchData($display)
- {
- if ($display)
- {
- $query = $this->CI->db->get_where($this->tableName,array($this->display => 0));
- }
- else
- {
- $query = $this->CI->db->get($this->tableName);
- }
- return $query->result_array();
- }
- /**
- *取某一条分类数据
- *@param $cid 分类ID
- */
- public function fetchOne($cid)
- {
- $this->CI->db->where($this->cid,$cid);
- $query = $this->CI->db->get($this->tableName);
- return $query->row_array(1);
- }
- /**
- *取出所有分类信息,返回数组,包括分类名称,一般用在select标签中显示
- * @param $fatherId 父类ID
- * @param $withself 查下级分类的时候,是否包含自己,默认false不包含。
- * @param $depth 所取分类的深度,值为0表示不限深度,会取所有的子分类。
- * @param $display 分类显示状态,
- */
- public function getAllCategory($fatherId = 0,$withself = false,$depth = 0,$display = false)
- {
- $result = array();
- $resArr = $this->fetchData($display); //获取所有分类信息
- // p($resArr);
- if($fatherId == 0 && $withself)
- {
- $root = array(
- $this->cid => 0,
- $this->fatherId => -1,
- $this->cateName => '根目录',
- $this->level => 0,
- $this->sort => 0
- );
- array_unshift($resArr, $root);
- }
- //p($resArr);
- if (empty($resArr))
- {
- return array();
- }
- //取得根目录
- foreach($resArr as $item)
- {
- if ($item[$this->fatherId] == $fatherId)
- {
- $level = $item[$this->level];
- }
- if ($withself)
- {
- if ($item[$this->cid] == $fatherId)
- {
- $result[] = $item;
- $level = $item[$this->level];
- break;
- }
- }
- }
- if (!isset($level))
- {
- return array();
- }
- $this->depth = $depth;
- $this->startLevel = $level;
- $nextLevel = $withself ? ($level + 1) : $level;
- return array_merge($result,$this->getChildren($resArr,$fatherId,$nextLevel));
- }
- /**
- * 取出某一分类下的所有ID,返回数组,fatherId = 0为根目录
- * @param $fatherId 父类ID
- * @param $widthself 取子分类时,是否包含自己,默认不包含
- * @param $depth 要读取的层级深度,默认查出所有子分类
- */
- public function getAllCategoryId($fatherId = 0,$widthself = false,$depth = 0,$display = false)
- {
- $idArr = array();
- if ($widthself)
- {
- array_push($idArr,$fatherId);
- }
- $cate = $this->getAllCategory($fatherId,$widthself,$depth,$display);
- foreach($cate as $item)
- {
- $idArr[] = $item[$this->cid];
- }
- return $idArr;
- }
- /**
- * 用于在下拉列表框中使用
- * @param $fatheriId 父类ID
- * @param $widthself 若取子分类的时候是否获取本身
- * @param $depth 分类深度
- * @param $display 分类显示状态
- * @param $selectId 用于编辑分类时自动设置默认状态为selected
- */
- public function getOptionStr($fatherId = 0,$withself = false,$depth = 0,$display = false,$selectId = 0)
- {
- $str = '';
- $cate = $this->getAllcategory($fatherId,$withself,$depth,$display);
- if (!empty($cate))
- {
- $line = '┣';
- foreach($cate as $item)
- {
- $selected = '';
- if ($selectId != 0 && $item[$this->cid] == $selectId)
- {
- $selected = 'selected';
- }
- $str .= '<option '.$selected.' value="'.$item[$this->cid].'">'.$line.str_repeat('━',($item[$this->level] - $this->startLevel)*2).$item[$this->cateName].'</option>';
- }
- }
- return $str;
- }
- /**
- * 用于列表显示,按ul li标签组织
- * @param $fatherId 父分类ID
- * @param $widthself 若取子分类的时候是否获取本身
- * @param $widthHref 是否提供超链接,即编辑和删除链接
- * @param $depth 分类深度
- */
- public function getListStr($fatherId = 0,$widthself = false,$withHref = true,$depth = 0,$display = false)
- {
- //开头
- $str = '';
- $startLevel = -1;
- $preLevel = 0;
- $cate = $this->getAllCategory($fatherId,$widthself,$depth,$display);
- if (!empty($cate))
- {
- foreach($cate as $item)
- {
- if ($startLevel < 0)
- {
- $startLevel = $item[$this->level];
- }
- if ($item[$this->level] < $preLevel) {
- $str .='</li>'.str_repeat('</ul></li>',$preLevel - $item[$this->level]);
- }
- elseif ($item[$this->level] > $preLevel) {
- $str .='<ul>';
- }
- else
- {
- $str .='</li>';
- }
- if ($withHref && $item[$this->cid]!= 0)
- {
- $str .= '<li>
- <span style="float:right;">
- '.($this->isDisplay($item[$this->cid]) ? "正常" : "待审").'
- <a href="'.site_url('cate/edit/'.$item[$this->cid]).'" class="mr50 ml200">edit</a>
- <a onclick=\'return confirm("Are your sure to delete?");\' href="'.site_url('cate/delete/'.$item[$this->cid]).'">del</a>
- </span>
- '.str_repeat(' ',($item[$this->level]-$this->startLevel)*4).'
- <span class="fb f16">'.($this->isChildren($item[$this->cid]) ? "+" : "-").'</span>
- <input type="text" name="cname" class="span2" value="'.$item[$this->cateName].'" style="border:0px;" />';
- }
- else
- {
- $str .= '<li>'.$item[$this->cateName];
- }
- $preLevel = $item[$this->level];
- }
- }
- //收尾
- $str .=str_repeat('</li></ul>',$preLevel - $startLevel + 1);
- return $str;
- }
- /**
- * 增加分类
- * @param $fatherId 父类ID
- * @param $cateName 分类名称
- * @param $content 分类介绍
- * @param $sort 分类排序, 只对同一级下的分类有用
- * @param $display 分类显示状态
- */
- public function addCategory($fatherId,$cateName,$content,$sort,$display)
- {
- //先获取父类的类别信息
- $parentInfo = $this->fetchOne($fatherId);
- //p($parentInfo);
- //获取分类的分类级别
- if (isset($parentInfo[$this->level]))
- {
- $level = $parentInfo[$this->level];
- }
- else
- {
- $level = 0;
- }
- $data = array(
- $this->fatherId => $fatherId,
- $this->cateName => $cateName,
- $this->content => $content,
- $this->sort => $sort,
- $this->level => $level + 1,
- $this->display => $display
- );
- $this->CI->db->insert($this->tableName,$data);
- return $this->CI->db->affected_rows();
- }
- /**
- * 删除分类
- * @param $cid 要删除的分类ID
- * @param $widthChild 是否删除下面的子分类,默认会删除
- */
- public function delCategory($cid,$widthChild = true)
- {
- if ($widthChild)
- {
- $idArr = $this->getAllCategoryId($cid,true);
- $this->CI->db->where_in($this->cid,$idArr);
- }
- else
- {
- $this->CI->db->where($this->cid,$cid);
- }
- $this->CI->db->delete($this->tableName);
- return $this->CI->db->affected_rows();
- }
- /**
- * 更新分类
- * @param $cid 要编辑的分类ID
- * @param $fatherId 父类ID
- * @param $cateName 分类的名称
- * @param $sort 分类排序
- * @param $display 分类显示状态
- */
- function editCategory($cid,$fatherId,$cateName,$content,$sort,$display)
- {
- //先获取父分类的信息
- $parentInfo = $this->fetchOne($fatherId);
- //获取当前等级
- if(isset($parentInfo[$this->level]))
- {
- $level = $parentInfo[$this->level];
- }
- else
- {
- $level = 0;
- }
- $currentInfo = $this->fetchOne($cid);
- //p($currentInfo);
- $newLevel = $level + 1;
- $levelDiff = $newLevel - $currentInfo[$this->level];
- //修改子分类的level
- if(0 != $levelDiff)
- {
- $childIdArr = $this->getAllCategoryId($cid);
- foreach($childIdArr as $item)
- {
- $this->CI->db->set($this->level, $this->level.'+'.$levelDiff, FALSE);
- $this->CI->db->where($this->cid, $item);
- $this->CI->db->update($this->tableName);
- }
- }
- //修改自己的信息
- $data = array(
- $this->fatherId => $fatherId,
- $this->cateName => $cateName,
- $this->level => $newLevel,
- $this->sort => $sort,
- $this->display => $display,
- );
- $this->CI->db->where($this->cid, $cid);
- $this->CI->db->update($this->tableName, $data);
- return $this->CI->db->affected_rows();
- }
- /**
- * 按顺序返回分类数组,用递归实现
- * @param unknown_type $cateArr
- * @param unknown_type $fatherId
- * @param unknown_type $level
- */
- private function getChildren($cateArr,$fatherId=0,$level = 1)
- {
- if($this->depth != 0 && ($level >=($this->depth + $this->startLevel)))
- {
- return array();
- }
- $resultArr = array();
- $childArr = array();
- //遍历当前父ID下的所有子分类
- foreach($cateArr as $item)
- {
- if($item[$this->fatherId] == $fatherId && ($item[$this->level] == $level))
- {
- //将子分类加入数组
- $childArr[] = $item;
- }
- }
- if(count($childArr) == 0)
- {
- //不存在下一级,无需继续
- return array();
- }
- //存在下一级,按sort排序先
- usort($childArr,array('Category','compareBysort'));
- foreach($childArr as $item)
- {
- $resultArr[] = $item;
- $temp = $this->getChildren($cateArr,$item[$this->cid],($item[$this->level] + 1));
- if(!empty($temp))
- {
- $resultArr = array_merge($resultArr, $temp);
- }
- }
- return $resultArr;
- }
- //比较函数,提供usort函数用
- private function compareBysort($a, $b)
- {
- if ($a == $b)
- {
- return 0;
- }
- return ($a[$this->sort] > $b[$this->sort]) ? +1 : -1;
- }
- //判断是否有子类别
- function isChildren($id)
- {
- //从数据库中取出只有fatherId字段的数据,返回数组
- $this->CI->db->select($this->fatherId);
- $query = $this->CI->db->get($this->tableName);
- $resArr = $query->result_array();
- foreach ($resArr as $v)
- {
- $arr[] = $v[$this->fatherId];
- }
- return (in_array($id,array_unique($arr))) ? true : false;
- }
- //判断状态是否启用
- function isDisplay($id)
- {
- $query = $this->fetchOne($id);
- return ($query[$this->display] == 1) ? true : false;
- }
- }
4、视图(源码在 application/views 文件夹)
分类显示视图:
<html>
- <head>
- <meta http-equiv="content-type" content="text/html; charset=utf-8">
- <title>Cate_index</title>
- <link rel="stylesheet" href="<?php echo $base_url; ?>/bootstrap/css/bootstrap.min.css" type="text/css" media="screen" charset="utf-8">
- <link rel="stylesheet" href="<?php echo $base_url; ?>/public/css/base.css" type="text/css" media="screen" charset="utf-8">
- </head>
- <body>
- <div class="w700 bc mt50">
- <h1 class="fb f20 mb20">分类列表显示</h1>
- <?php echo $tree_str ?>
- </div>
- </body>
- </html>
分类添加和编辑视图:
- <html>
- <head>
- <meta http-equiv="content-type" content="text/html; charset=utf-8">
- <title>Cate_edit</title>
- <link rel="stylesheet" href="<?php echo $base_url; ?>/bootstrap/css/bootstrap.min.css" type="text/css" media="screen" charset="utf-8">
- <link rel="stylesheet" href="<?php echo $base_url; ?>/public/css/base.css" type="text/css" media="screen" charset="utf-8">
- </head>
- <body>
- <?php echo form_open((($cid = $this->uri->segment(3)) === FALSE) ? 'cate/insert' : 'cate/update');?>
- <?php echo form_hidden('cid', ($cid === FALSE ? '' : $this->uri->segment(3))); ?>
- <table class="table table-bordered w500 mt50 bc">
- <tr>
- <td width='25%'>选择父分类:</td>
- <td>
- <select name='fatherId'><?php echo $option_str; ?></select>
- </td>
- </tr>
- <tr>
- <td>分类名称:</td>
- <td><?php echo form_input('cateName',($cid === FALSE) ? '' : $post['cateName']); ?></td>
- </tr>
- <tr>
- <td>分类介绍:</td>
- <td><?php echo form_textarea('content',($cid === FALSE) ? '' : $post['content']); ?></td>
- </tr>
- <tr>
- <td>分类排序:</td>
- <td><?php echo form_input('sort',($cid === FALSE) ? '' : $post['sort'],'class="span1"'); ?></td>
- </tr>
- <tr>
- <td>是否启用:</td>
- <td>
- <?php echo form_checkbox("display",'1',($cid === FALSE ? '' : ($post['display']==='1' ? TRUE : FALSE))) ;?>
- </td>
- </tr>
- <tr>
- <td colspan='2' class="form-actions">
- <?php echo form_submit("submit","提交","class='btn btn-primary'"); ?>
- <?php echo form_reset("reset","重置","class='btn'"); ?>
- </td>
- </tr>
- </table>
- <?php echo form_close(); ?>
- </body>
- </html>
5、应用
(1)、先下载附件,解压之后,拷贝到网站根目录下;
(2)、找到文件ci_cate.sql,建库建表;
(3)、修改配置文件CI_cate/application/config/database.php,只需设置$db['default']['password'] ='你的数据库密码'; ,大概在53行;
(4)、浏览器输入http://localhost/CI_cate/index.php/cate/index即可访问分类显示页
输入http://localhost/CI_cate/index.php/cate/edit即可访问添加分类页。
代码示例 CI_cate.rar