【軍哥談CI框架】之無限分類類庫的實現和應用

你們好,我是軍哥,英文名:JayJun,一直想跟大夥交流一下學習和使用CI的心得和經驗,最近也在用CI寫一個在線書城項目,已經完成80%,其中有用到無限分類,關於無限分類,有許多的實現方式,今個呢,軍哥,跟你們先分享本身寫的無限分類類庫,只適合CI框架喲,固然你也能夠修改後使用到其它地方,接着咱們會在CI框架中應用一下(詳見附件中代碼示例)。這裏要求你有必定的面向對象基礎,固然瞭解和熟悉CI(或其它PHP框架)就更好啦。 javascript

另外,軍哥在代碼中應用了市面上熱門的一個前端UI框架——bootstarp,這個框架在爲咱們實現頁面樣式方面是表現的至關給力!詳見:bootstrap前端UI框架中文版官網php

好了,不廢話啦,軍哥語文學滴很差(小學沒少挨老師打手掌心呀),就直接上代碼了。有學習和研究CI的,歡迎拍磚!!! css

一、先看效果,有圖有真相; html

分頁顯示頁: 前端

添加分類頁: java

編輯分類頁: git

二、控制器(源碼在 application/controllers 文件夾) github

//無限分類控制器功能
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>";
        }
    }
三、無限分類類庫(源碼在 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;
            }
    }
四、視圖 源碼在 application/views 文件夾  

分類顯示視圖:
sql

<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>
五、應用
(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便可訪問添加分類頁。 數據庫

附件下載:http://bbs.lampbrother.net/job.php?action=download&aid=22124

相關文章
相關標籤/搜索