当前位置: 代码迷 >> Web前端 >> 军哥途CI框架之无限分类类库的实现和应用
  详细解决方案

军哥途CI框架之无限分类类库的实现和应用

热度:423   发布时间:2012-09-18 16:21:42.0
军哥谈CI框架之无限分类类库的实现和应用
大家好,,我是军哥,英文名:JayJun,一直想跟大伙交流一下学习和使用CI的心得和经验,最近也在用CI写一个在线书城项目,已经完成80%,其中有用到无限分类,关于无限分类,有许多的实现方式,今个呢,军哥,跟大家先分享自己写的无限分类类库,只适合CI框架哟,当然你也可以修改后使用到其它地方,接着我们会在CI框架中应用一下(详见附件中代码示例)。这里要求你有一定的面向对象基础,当然了解和熟悉CI(或其它PHP框架)就更好啦。


另外,军哥在代码中应用了市面上热门的一个前端UI框架――bootstarp,这个框架在为我们实现页面样式方面是表现的相当给力!详见:bootstrap前端UI框架中文版官网。



好了,不废话啦,军哥语文学滴不好(小学没少挨老师打手掌心呀),就直接上代码啦!


有学习和研究CI的,欢迎拍砖!!! 代码示例 CI_cate.rar 1、先看效果,有图有真相;
分类显示页:


添加分类页:


编辑分类页:


2、控制器(源码在 application/controllers 文件夹)
  1. //无限分类控制器功能
  2. class cate extends CI_Controller
  3. {
  4. private $_cate_url = 'cate/'; //无限分类视图路径
  5. public function __construct()
  6. {
  7. parent::__construct();
  8. $this->base_url = $this->config->item("base_url");
  9. $this->load->library('category');
  10. }
  11. //显示分类
  12. public function index()
  13. {
  14. $data['base_url'] = $this->base_url;
  15. $data['tree_str'] = $this->category->getListStr();
  16. $this->load->view($this->_cate_url.'cate_index',$data);
  17. }
  18. //编辑分类
  19. public function edit($cid = '')
  20. {
  21. $data['base_url'] = $this->base_url;
  22. if ($cid != '')
  23. {
  24. $query = $data['post'] = $this->category->fetchOne($cid);
  25. $pid = $query['fatherId'];
  26. $data['option_str'] = $this->category->getOptionStr(0,true,0,false,$pid);
  27. }
  28. else
  29. {
  30. $data['option_str'] = $this->category->getOptionStr(0,true,0,false,0);
  31. }
  32. $this->load->view($this->_cate_url.'cate_edit',$data);
  33. }
  34. //执行插入分类操作
  35. public function insert()
  36. {
  37. //获取表单提交的信息
  38. $fatherId = $this->input->post('fatherId');
  39. $cateName = $this->input->post('cateName');
  40. $content = $this->input->post('content');
  41. $sort = $this->input->post('sort');
  42. $display = $this->input->post('display');
  43. if ($this->category->addCategory($fatherId,$cateName,$content,$sort,$display) > 0)
  44. {
  45. echo "<script language=\"javascript\">alert('添加成功!')</script>";
  46. }
  47. else
  48. {
  49. echo "<script language=\"javascript\">alert('添加失败!')</script>";
  50. }
  51. echo "<script language=\"javascript\">history.go(-1);</script>";
  52. }
  53. //执行编辑操作
  54. function update($cid = '')
  55. {
  56. $cid = ($cid === '') ? $this->input->post('cid') : $cid;
  57. if ($cid !== '')
  58. {
  59. //获取表单提交的信息
  60. $fatherId = $this->input->post('fatherId');
  61. $cateName = $this->input->post('cateName');
  62. $content = $this->input->post('content');
  63. $sort = $this->input->post('sort');
  64. $display = $this->input->post('display');
  65. if ($this->category->editCategory($cid,$fatherId,$cateName,$content,$sort,$display) > 0)
  66. {
  67. echo "<script language=\"javascript\">alert('更新成功!')</script>";
  68. }
  69. else
  70. {
  71. echo "<script language=\"javascript\">alert('更新失败!')</script>";
  72. }
  73. }
  74. echo "<script language=\"javascript\">history.go(-1);</script>";
  75. }
  76. //执行删除操作
  77. function delete($cid = '')
  78. {
  79. if ($cid !== '')
  80. {
  81. if ($this->category->delCategory($cid) > 0)
  82. {
  83. echo "<script language=\"javascript\">alert('删除成功!')</script>";
  84. }
  85. else
  86. {
  87. echo "<script language=\"javascript\">alert('删除失败!')</script>";
  88. }
  89. }
  90. echo "<script language=\"javascript\">history.go(-1);</script>";
  91. }
  92. }


3、无限分类类库(源码在 application/libraries 文件夹);
/*==================================================================*/
  1. /* 文件名:Category.php */
  2. /* 功能:实现无限分类的增删改查,用于codeigniter框架,
  3. 也可以修改后用于其它用途。 */
  4. /* 作者:张礼军
  5. /* 英文名:JayJun QQ:413920268 */
  6. /* 创建时间:2012-08-29 */
  7. /* 最后修改时间:2012-08-31 */
  8. /* copyright (c)2012 jayjun0805@sina.com */
  9. /*==================================================================*/
  10. if (!defined('BASEPATH')) exit('No direct script access allowed');
  11. class Category {
  12. private $CI; //CI对象
  13. private $tableName; //要操作的表名
  14. //表的七个字段
  15. private $cid; //分类ID
  16. private $fatherId; //父分类ID
  17. private $cateName; //分类名称
  18. private $sort; //分类排序,在同一父级下有多级时,用于排序
  19. private $content; //分类介绍
  20. private $level; //分类等级,即当前目录的级别
  21. private $display; //分类显示状态
  22. //所取分类的深度
  23. private $depth = 0;
  24. private $startLevel = 0;
  25. /**
  26. * 构造函数
  27. * @param $arr 参数包括表名,及分类表的七个字段名,如果没有定义,则采用默认,
  28. * 默认值
  29. * 表名:category
  30. * 分类ID:cid
  31. * 父ID:fatherId
  32. * 分类名称:cateName
  33. * 分类排序:sort
  34. * 分类介绍:content
  35. * 分类等级:level
  36. * 分类显示状态:display
  37. */
  38. public function __construct($arr = array())
  39. {
  40. //通过引用的方式赋给变量来初始化原始的CodeIgniter对象
  41. $this->CI = &get_instance();
  42. //初始化表参数
  43. $this->tableName = (isset($arr['tableName'])) ? $arr['tableName'] : 'category';
  44. $this->cid = (isset($arr['cid'])) ? $arr['cid'] : 'cid';
  45. $this->fatherId = (isset($arr['fatherId'])) ? $arr['fatherId'] : 'fatherId';
  46. $this->cateName = (isset($arr['cateName'])) ? $arr['cateName'] : 'cateName';
  47. $this->sort = (isset($arr['sort'])) ? $arr['sort'] : 'sort';
  48. $this->content = (isset($arr['content'])) ? $arr['content'] : 'content';
  49. $this->level = (isset($arr['level'])) ? $arr['level'] : 'level';
  50. $this->display = (isset($arr['display'])) ? $arr['display'] : 'display';
  51. }
  52. /**
  53. * 从数据库取所有分类数据,返回数组
  54. */
  55. public function fetchData($display)
  56. {
  57. if ($display)
  58. {
  59. $query = $this->CI->db->get_where($this->tableName,array($this->display => 0));
  60. }
  61. else
  62. {
  63. $query = $this->CI->db->get($this->tableName);
  64. }
  65. return $query->result_array();
  66. }
  67. /**
  68. *取某一条分类数据
  69. *@param $cid 分类ID
  70. */
  71. public function fetchOne($cid)
  72. {
  73. $this->CI->db->where($this->cid,$cid);
  74. $query = $this->CI->db->get($this->tableName);
  75. return $query->row_array(1);
  76. }
  77. /**
  78. *取出所有分类信息,返回数组,包括分类名称,一般用在select标签中显示
  79. * @param $fatherId 父类ID
  80. * @param $withself 查下级分类的时候,是否包含自己,默认false不包含。
  81. * @param $depth 所取分类的深度,值为0表示不限深度,会取所有的子分类。
  82. * @param $display 分类显示状态,
  83. */
  84. public function getAllCategory($fatherId = 0,$withself = false,$depth = 0,$display = false)
  85. {
  86. $result = array();
  87. $resArr = $this->fetchData($display); //获取所有分类信息
  88. // p($resArr);
  89. if($fatherId == 0 && $withself)
  90. {
  91. $root = array(
  92. $this->cid => 0,
  93. $this->fatherId => -1,
  94. $this->cateName => '根目录',
  95. $this->level => 0,
  96. $this->sort => 0
  97. );
  98. array_unshift($resArr, $root);
  99. }
  100. //p($resArr);
  101. if (empty($resArr))
  102. {
  103. return array();
  104. }
  105. //取得根目录
  106. foreach($resArr as $item)
  107. {
  108. if ($item[$this->fatherId] == $fatherId)
  109. {
  110. $level = $item[$this->level];
  111. }
  112. if ($withself)
  113. {
  114. if ($item[$this->cid] == $fatherId)
  115. {
  116. $result[] = $item;
  117. $level = $item[$this->level];
  118. break;
  119. }
  120. }
  121. }
  122. if (!isset($level))
  123. {
  124. return array();
  125. }
  126. $this->depth = $depth;
  127. $this->startLevel = $level;
  128. $nextLevel = $withself ? ($level + 1) : $level;
  129. return array_merge($result,$this->getChildren($resArr,$fatherId,$nextLevel));
  130. }
  131. /**
  132. * 取出某一分类下的所有ID,返回数组,fatherId = 0为根目录
  133. * @param $fatherId 父类ID
  134. * @param $widthself 取子分类时,是否包含自己,默认不包含
  135. * @param $depth 要读取的层级深度,默认查出所有子分类
  136. */
  137. public function getAllCategoryId($fatherId = 0,$widthself = false,$depth = 0,$display = false)
  138. {
  139. $idArr = array();
  140. if ($widthself)
  141. {
  142. array_push($idArr,$fatherId);
  143. }
  144. $cate = $this->getAllCategory($fatherId,$widthself,$depth,$display);
  145. foreach($cate as $item)
  146. {
  147. $idArr[] = $item[$this->cid];
  148. }
  149. return $idArr;
  150. }
  151. /**
  152. * 用于在下拉列表框中使用
  153. * @param $fatheriId 父类ID
  154. * @param $widthself 若取子分类的时候是否获取本身
  155. * @param $depth 分类深度
  156. * @param $display 分类显示状态
  157. * @param $selectId 用于编辑分类时自动设置默认状态为selected
  158. */
  159. public function getOptionStr($fatherId = 0,$withself = false,$depth = 0,$display = false,$selectId = 0)
  160. {
  161. $str = '';
  162. $cate = $this->getAllcategory($fatherId,$withself,$depth,$display);
  163. if (!empty($cate))
  164. {
  165. $line = '┣';
  166. foreach($cate as $item)
  167. {
  168. $selected = '';
  169. if ($selectId != 0 && $item[$this->cid] == $selectId)
  170. {
  171. $selected = 'selected';
  172. }
  173. $str .= '<option '.$selected.' value="'.$item[$this->cid].'">'.$line.str_repeat('━',($item[$this->level] - $this->startLevel)*2).$item[$this->cateName].'</option>';
  174. }
  175. }
  176. return $str;
  177. }
  178. /**
  179. * 用于列表显示,按ul li标签组织
  180. * @param $fatherId 父分类ID
  181. * @param $widthself 若取子分类的时候是否获取本身
  182. * @param $widthHref 是否提供超链接,即编辑和删除链接
  183. * @param $depth 分类深度
  184. */
  185. public function getListStr($fatherId = 0,$widthself = false,$withHref = true,$depth = 0,$display = false)
  186. {
  187. //开头
  188. $str = '';
  189. $startLevel = -1;
  190. $preLevel = 0;
  191. $cate = $this->getAllCategory($fatherId,$widthself,$depth,$display);
  192. if (!empty($cate))
  193. {
  194. foreach($cate as $item)
  195. {
  196. if ($startLevel < 0)
  197. {
  198. $startLevel = $item[$this->level];
  199. }
  200. if ($item[$this->level] < $preLevel) {
  201. $str .='</li>'.str_repeat('</ul></li>',$preLevel - $item[$this->level]);
  202. }
  203. elseif ($item[$this->level] > $preLevel) {
  204. $str .='<ul>';
  205. }
  206. else
  207. {
  208. $str .='</li>';
  209. }
  210. if ($withHref && $item[$this->cid]!= 0)
  211. {
  212. $str .= '<li>
  213. <span style="float:right;">
  214. '.($this->isDisplay($item[$this->cid]) ? "正常" : "待审").'
  215. <a href="'.site_url('cate/edit/'.$item[$this->cid]).'" class="mr50 ml200">edit</a>
  216. <a onclick=\'return confirm("Are your sure to delete?");\' href="'.site_url('cate/delete/'.$item[$this->cid]).'">del</a>
  217. </span>
  218. '.str_repeat(' ',($item[$this->level]-$this->startLevel)*4).'
  219. <span class="fb f16">'.($this->isChildren($item[$this->cid]) ? "+" : "-").'</span>
  220. <input type="text" name="cname" class="span2" value="'.$item[$this->cateName].'" style="border:0px;" />';
  221. }
  222. else
  223. {
  224. $str .= '<li>'.$item[$this->cateName];
  225. }
  226. $preLevel = $item[$this->level];
  227. }
  228. }
  229. //收尾
  230. $str .=str_repeat('</li></ul>',$preLevel - $startLevel + 1);
  231. return $str;
  232. }
  233. /**
  234. * 增加分类
  235. * @param $fatherId 父类ID
  236. * @param $cateName 分类名称
  237. * @param $content 分类介绍
  238. * @param $sort 分类排序, 只对同一级下的分类有用
  239. * @param $display 分类显示状态
  240. */
  241. public function addCategory($fatherId,$cateName,$content,$sort,$display)
  242. {
  243. //先获取父类的类别信息
  244. $parentInfo = $this->fetchOne($fatherId);
  245. //p($parentInfo);
  246. //获取分类的分类级别
  247. if (isset($parentInfo[$this->level]))
  248. {
  249. $level = $parentInfo[$this->level];
  250. }
  251. else
  252. {
  253. $level = 0;
  254. }
  255. $data = array(
  256. $this->fatherId => $fatherId,
  257. $this->cateName => $cateName,
  258. $this->content => $content,
  259. $this->sort => $sort,
  260. $this->level => $level + 1,
  261. $this->display => $display
  262. );
  263. $this->CI->db->insert($this->tableName,$data);
  264. return $this->CI->db->affected_rows();
  265. }
  266. /**
  267. * 删除分类
  268. * @param $cid 要删除的分类ID
  269. * @param $widthChild 是否删除下面的子分类,默认会删除
  270. */
  271. public function delCategory($cid,$widthChild = true)
  272. {
  273. if ($widthChild)
  274. {
  275. $idArr = $this->getAllCategoryId($cid,true);
  276. $this->CI->db->where_in($this->cid,$idArr);
  277. }
  278. else
  279. {
  280. $this->CI->db->where($this->cid,$cid);
  281. }
  282. $this->CI->db->delete($this->tableName);
  283. return $this->CI->db->affected_rows();
  284. }
  285. /**
  286. * 更新分类
  287. * @param $cid 要编辑的分类ID
  288. * @param $fatherId 父类ID
  289. * @param $cateName 分类的名称
  290. * @param $sort 分类排序
  291. * @param $display 分类显示状态
  292. */
  293. function editCategory($cid,$fatherId,$cateName,$content,$sort,$display)
  294. {
  295. //先获取父分类的信息
  296. $parentInfo = $this->fetchOne($fatherId);
  297. //获取当前等级
  298. if(isset($parentInfo[$this->level]))
  299. {
  300. $level = $parentInfo[$this->level];
  301. }
  302. else
  303. {
  304. $level = 0;
  305. }
  306. $currentInfo = $this->fetchOne($cid);
  307. //p($currentInfo);
  308. $newLevel = $level + 1;
  309. $levelDiff = $newLevel - $currentInfo[$this->level];
  310. //修改子分类的level
  311. if(0 != $levelDiff)
  312. {
  313. $childIdArr = $this->getAllCategoryId($cid);
  314. foreach($childIdArr as $item)
  315. {
  316. $this->CI->db->set($this->level, $this->level.'+'.$levelDiff, FALSE);
  317. $this->CI->db->where($this->cid, $item);
  318. $this->CI->db->update($this->tableName);
  319. }
  320. }
  321. //修改自己的信息
  322. $data = array(
  323. $this->fatherId => $fatherId,
  324. $this->cateName => $cateName,
  325. $this->level => $newLevel,
  326. $this->sort => $sort,
  327. $this->display => $display,
  328. );
  329. $this->CI->db->where($this->cid, $cid);
  330. $this->CI->db->update($this->tableName, $data);
  331. return $this->CI->db->affected_rows();
  332. }
  333. /**
  334. * 按顺序返回分类数组,用递归实现
  335. * @param unknown_type $cateArr
  336. * @param unknown_type $fatherId
  337. * @param unknown_type $level
  338. */
  339. private function getChildren($cateArr,$fatherId=0,$level = 1)
  340. {
  341. if($this->depth != 0 && ($level >=($this->depth + $this->startLevel)))
  342. {
  343. return array();
  344. }
  345. $resultArr = array();
  346. $childArr = array();
  347. //遍历当前父ID下的所有子分类
  348. foreach($cateArr as $item)
  349. {
  350. if($item[$this->fatherId] == $fatherId && ($item[$this->level] == $level))
  351. {
  352. //将子分类加入数组
  353. $childArr[] = $item;
  354. }
  355. }
  356. if(count($childArr) == 0)
  357. {
  358. //不存在下一级,无需继续
  359. return array();
  360. }
  361. //存在下一级,按sort排序先
  362. usort($childArr,array('Category','compareBysort'));
  363. foreach($childArr as $item)
  364. {
  365. $resultArr[] = $item;
  366. $temp = $this->getChildren($cateArr,$item[$this->cid],($item[$this->level] + 1));
  367. if(!empty($temp))
  368. {
  369. $resultArr = array_merge($resultArr, $temp);
  370. }
  371. }
  372. return $resultArr;
  373. }
  374. //比较函数,提供usort函数用
  375. private function compareBysort($a, $b)
  376. {
  377. if ($a == $b)
  378. {
  379. return 0;
  380. }
  381. return ($a[$this->sort] > $b[$this->sort]) ? +1 : -1;
  382. }
  383. //判断是否有子类别
  384. function isChildren($id)
  385. {
  386. //从数据库中取出只有fatherId字段的数据,返回数组
  387. $this->CI->db->select($this->fatherId);
  388. $query = $this->CI->db->get($this->tableName);
  389. $resArr = $query->result_array();
  390. foreach ($resArr as $v)
  391. {
  392. $arr[] = $v[$this->fatherId];
  393. }
  394. return (in_array($id,array_unique($arr))) ? true : false;
  395. }
  396. //判断状态是否启用
  397. function isDisplay($id)
  398. {
  399. $query = $this->fetchOne($id);
  400. return ($query[$this->display] == 1) ? true : false;
  401. }
  402. }

4、视图源码在 application/views 文件夹

分类显示视图:
<html>
  1. <head>
  2. <meta http-equiv="content-type" content="text/html; charset=utf-8">
  3. <title>Cate_index</title>
  4. <link rel="stylesheet" href="<?php echo $base_url; ?>/bootstrap/css/bootstrap.min.css" type="text/css" media="screen" charset="utf-8">
  5. <link rel="stylesheet" href="<?php echo $base_url; ?>/public/css/base.css" type="text/css" media="screen" charset="utf-8">
  6. </head>
  7. <body>
  8. <div class="w700 bc mt50">
  9. <h1 class="fb f20 mb20">分类列表显示</h1>
  10. <?php echo $tree_str ?>
  11. </div>
  12. </body>
  13. </html>

分类添加和编辑视图:
  1. <html>
  2. <head>
  3. <meta http-equiv="content-type" content="text/html; charset=utf-8">
  4. <title>Cate_edit</title>
  5. <link rel="stylesheet" href="<?php echo $base_url; ?>/bootstrap/css/bootstrap.min.css" type="text/css" media="screen" charset="utf-8">
  6. <link rel="stylesheet" href="<?php echo $base_url; ?>/public/css/base.css" type="text/css" media="screen" charset="utf-8">
  7. </head>
  8. <body>
  9. <?php echo form_open((($cid = $this->uri->segment(3)) === FALSE) ? 'cate/insert' : 'cate/update');?>
  10. <?php echo form_hidden('cid', ($cid === FALSE ? '' : $this->uri->segment(3))); ?>
  11. <table class="table table-bordered w500 mt50 bc">
  12. <tr>
  13. <td width='25%'>选择父分类:</td>
  14. <td>
  15. <select name='fatherId'><?php echo $option_str; ?></select>
  16. </td>
  17. </tr>
  18. <tr>
  19. <td>分类名称:</td>
  20. <td><?php echo form_input('cateName',($cid === FALSE) ? '' : $post['cateName']); ?></td>
  21. </tr>
  22. <tr>
  23. <td>分类介绍:</td>
  24. <td><?php echo form_textarea('content',($cid === FALSE) ? '' : $post['content']); ?></td>
  25. </tr>
  26. <tr>
  27. <td>分类排序:</td>
  28. <td><?php echo form_input('sort',($cid === FALSE) ? '' : $post['sort'],'class="span1"'); ?></td>
  29. </tr>
  30. <tr>
  31. <td>是否启用:</td>
  32. <td>
  33. <?php echo form_checkbox("display",'1',($cid === FALSE ? '' : ($post['display']==='1' ? TRUE : FALSE))) ;?>
  34. </td>
  35. </tr>
  36. <tr>
  37. <td colspan='2' class="form-actions">
  38. <?php echo form_submit("submit","提交","class='btn btn-primary'"); ?>
  39. <?php echo form_reset("reset","重置","class='btn'"); ?>
  40. </td>
  41. </tr>
  42. </table>
  43. <?php echo form_close(); ?>
  44. </body>
  45. </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

  相关解决方案