大家好,我是军哥,英文名:JayJun,一直想跟大伙交流一下学习和使用CI的心得和经验,最近也在用CI写一个在线书城项目,已经完成80%,其中有用到无限分类,关于无限分类,有许多的实现方式,今个呢,军哥,跟大家先分享自己写的无限分类类库,只适合CI框架哟,当然你也可以修改后使用到其它地方,接着我们会在CI框架中应用一下(详见附件中代码示例)。这里要求你有一定的面向对象基础,当然了解和熟悉CI(或其它PHP框架)就更好啦。
另外,军哥在代码中应用了市面上热门的一个前端UI框架——bootstarp,这个框架在为我们实现页面样式方面是表现的相当给力!详见:bootstrap前端UI框架中文版官网。
好了,不废话啦,军哥语文学滴不好(小学没少挨老师打手掌心呀),就直接上代码了。有学习和研究CI的,欢迎拍砖!!!
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 [email protected] */ /*==================================================================*/ 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、应用
(4)、浏览器输入http://localhost/CI_cate/index.php/cate/index即可访问分类显示页 ,输入http://localhost/CI_cate/index.php/cate/edit即可访问添加分类页。
附件下载:http://bbs.lampbrother.net/job.php?action=download&aid=22124