iloveagan 发表于 2013-3-3 11:21:30

CI控制器相似业务重复问题的疑惑

背景:建立了一个类似新闻管理系统的后台,但是分几个栏目,包含:新闻管理,文章管理(与新闻栏目不一样),人物管理……
功能:每个栏目的功能都比较相似,都含有一个添加信息,修改信息,管理列表(在此列表中有删除按键,可删除信息)的功能
问题:现在的问题是这样的,对每一个模块都定义了一个控制器,news,article,person……,这些控制器下都有add/edit(显示添加/编辑信息的页面),add_action/edit_action处理添加/编辑页面提交的表单信息),delete_action(删除信息),manage(显示信息列表)这几个基本的方法。
最后的疑惑:做了这三个模块后,发现他们都是如此的相似,当要写person这个模块时,直接就是把news的复制一份,然后修改一下变量,做一下简单的改变即可。有没有什么好的办法把这种相似的业务处理抽象出来?单独拿出来?

// 以下是文章栏目的控制器部分方法
class Article extends MY_Controller
{
    function __construct()
    {
      parent::__construct();
      
      // 后台登录验证
      $this->check_login();
      $this->load->model('article_m');
      
      // 加载文章的语言包
      $this->load->language('article');
      
      $this->validate_data = array(
                array('field' => 'title', 'label' => 'lang:article_title', 'rules' => 'trim|required|max_length|xss_clean'),
                array('field' => 'editor', 'label' => 'lang:article_editor', 'rules' => 'trim|required|max_length'),
                array('field' => 'author', 'label' => 'lang:article_author', 'rules' => 'trim|required|max_length'),
                array('field' => 'source', 'label' => 'lang:article_source', 'rules' => 'trim|required|max_length'),
                array('field' => 'path', 'label' => 'lang:article_attachment', 'rules' => 'trim|max_length'),
                array('field' => 'content', 'label' => 'lang:article_content', 'rules' => 'trim|required'),
                array('field' => 'keyword', 'label' => 'lang:com_keyword', 'rules' => 'trim|max_length'),
                array('field' => 'classid', 'label' => 'lang:com_column_name', 'rules' => 'trim|required|is_natural_no_zero'),
                array('field' => 'releasename', 'label' => 'lang:com_releasename', 'rules' => 'trim|required|max_length'),
                array('field' => 'remark', 'label' => 'lang:com_remark', 'rules' => 'trim|max_length'),
                );
    }
   
    function index($page = '')
    {
      $this->manage($page);
    }
   
    /**
   * 显示文章列表
   * @param int $page 显示的页码
   */
    function manage($page = '')
    {
      // 获取要显示的页数
      $page         = empty($page) ? 1 : abs(intval($page));
   
      // 组织分页信息
      $config['base_url']      = base_url('article/manage');
      $config['total_rows']    = $this->article_m->get_article_count();
      
      $page_data = $this->get_page($config);
      $data['page']   = $page_data['page'];
      $order             = 'istop desc,isrecommend desc,id desc';
   
      // 查询文章
      $article      = $this->article_m->show_article($page_data['limit'], $order);
   
      // 文章信息列表数组
      $i = 1;
      foreach ($article as $key => $row)
      {
            $article[$key]['ordernum']   = ($page - 1) * $page_data['per_page'] + $i;
            $article[$key]['createtime']    = date(config_item('date_format'),$row['createtime']);
            $article[$key]['updatetime']    = date(config_item('date_format'),$row['updatetime']);
            $article[$key]['isactive']   = $row['isactive'] == 0 ? $this->lang->line('com_sign_inactive') : $this->lang->line('com_sign_active');
            $article[$key]['isverify']   = $row['isverify'] == 0 ? $this->lang->line('com_sign_not_verify') : $this->lang->line('com_sign_verify');
            $article[$key]['isrecommend'] = $row['isrecommend'] == 1 ? $this->lang->line('com_sign_recommend') : '';
            $article[$key]['istop']         = $row['istop'] == 1 ? $this->lang->line('com_sign_top') : '';
            $i++;
      }
   
      $data['header']         = $this->header;
      $data['title']            = $this->lang->line('article_title_list');
      $data['page_label']      = $this->lang->line('article_page_label');
      $data['nav_label']         = $this->lang->line('com_navigate_label');
      $data['article']   = $article;
      $this->load->view('article_list',$data);
    }
   
    /**
   * ajax删除文章,返回json结果
   */
    function delete_action()
    {
      $result = array('error' => FALSE, 'message' => $this->lang->line('msg_operation_success'));
   
      // 对表单数据做判断
      $validate = $this->validation(array('field' => 'id[]', 'label' => 'lang:article_id', 'rules' => 'trim|required|is_natural|xss_clean'));
      if (TRUE !== $validate)
      {
            $result['error']   = TRUE;
            $result['message']   = $validate;
            echo json_encode($result);
            return ;
      }
   
      // 获取文章ID值,并放入数组
      $id = $this->input->post('id');
      if (TRUE === $this->article_m->delete_article_by_id($id))
      {
            echo json_encode($result);
            return ;
      }
      else
      {
            $result['error']   = TRUE;
            $result['message']   = $this->lang->line('msg_operation_failed');
            echo json_encode($result);
            return ;
      }
    }
   
    /**
   * 显示文章添加页面
   */
    function add()
    {
      $data['header']         = $this->header;// 公用头部
      $data['title']            = $this->lang->line('article_title_add');
      $data['page_label']      = $this->lang->line('article_page_label'); // 页面标签,即栏目名称
      $data['nav_label']         = $this->lang->line('com_navigate_label'); // 导航标签
      $data['loginname']         = $this->loginname;
      $data['class']             = $this->get_column_as_array(); // 栏目分类
      $this->load->view('article_add', $data);
    }


// 以下是新闻栏目的控制器

class News extends MY_Controller
{
    function __construct()
    {
      parent::__construct();
      
      // 后台登录验证
      $this->check_login();
      $this->load->model('news_m');

      // 加载文章的语言包
      $this->load->language('news');
      
      $this->validate_data = array(
                array('field' => 'title', 'label' => 'lang:news_title', 'rules' => 'trim|required|max_length|xss_clean'),
                array('field' => 'author', 'label' => 'lang:news_author', 'rules' => 'trim|required|max_length'),
                array('field' => 'keyword', 'label' => 'lang:com_keyword', 'rules' => 'trim|max_length'),
                array('field' => 'classid', 'label' => 'lang:com_column_name', 'rules' => 'trim|required|is_natural_no_zero'),
                array('field' => 'source', 'label' => 'lang:news_source', 'rules' => 'trim|required|max_length'),
                array('field' => 'releasename', 'label' => 'lang:com_releasename', 'rules' => 'trim|required|max_length'),
                array('field' => 'picturepath', 'label' => 'lang:news_pictures', 'rules' => 'trim|max_length'),
                array('field' => 'content', 'label' => 'lang:news_source', 'rules' => 'trim|required'),
                array('field' => 'remark', 'label' => 'lang:com_remark', 'rules' => 'trim|max_length'),
                );
    }
   
    function index($page = '')
    {
      $this->manage($page);
    }
   
    /**
   * 新闻列表显示
   * @param int $page 当前显示页码
   */
    function manage($page = '')
    {
      // 获取要显示的页数
      $page         = empty($page) ? 1 : abs(intval($page));
      
      // 组织分页信息
      $config['base_url']      = base_url('news/manage');
      $config['total_rows']    = $this->news_m->get_news_count();
      
      $page_data = $this->get_page($config);
      $data['page']   = $page_data['page'];
      $order             = 'istop desc,isrecommend desc,id desc';

      // 查询新闻
      $news      = $this->news_m->show_news($page_data['limit'], $order);
      
      // 新闻信息列表数组
      $i = 1;
      foreach ($news as $key => $row)
      {
            $news[$key]['ordernum']   = ($page - 1) * $page_data['per_page'] + $i;
            $news[$key]['createtime']    =date(config_item('date_format'),$row['createtime']);
            $news[$key]['updatetime']    =date(config_item('date_format'),$row['updatetime']);
            $news[$key]['isactive']   = $row['isactive'] == 0 ? $this->lang->line('com_sign_inactive') : $this->lang->line('com_sign_active');
            $news[$key]['isverify']   = $row['isverify'] == 0 ? $this->lang->line('com_sign_not_verify') : $this->lang->line('com_sign_verify');
            $news[$key]['isrecommend'] = $row['isrecommend'] == 1 ? $this->lang->line('com_sign_recommend') : '';
            $news[$key]['istop']         = $row['istop'] == 1 ? $this->lang->line('com_sign_top') : '';
            $news[$key]['ispic']         = $row['ispic'] == 1 ? $this->lang->line('com_sign_picture') : '';
            $i++;
      }
      
      $data['header']         = $this->header;
      $data['title']            = $this->lang->line('news_title_list');
      $data['page_label']      = $this->lang->line('news_page_label');
      $data['nav_label']         = $this->lang->line('com_navigate_label');
      $data['news']             = $news;
      $this->load->view('news_list',$data);
    }
   
    /**
   * 显示添加新闻页面
   */
    function add()
    {
      $data['header']         = $this->header;
      $data['title']            = $this->lang->line('news_title_add');
      $data['page_label']      = $this->lang->line('news_page_label');
      $data['nav_label']         = $this->lang->line('com_navigate_label');
      $data['loginname']         = $this->loginname;
      $data['class']             = $this->get_column_as_array();
      $this->load->view('news_add', $data);
    }

    /**
   * AJAX方式删除新闻,如果是图片新闻也删除其所属的图片,返回json信息
   */
    function delete_action()
    {
      $result = array('error' => FALSE, 'message' => $this->lang->line('msg_operation_success'));

      // 对表单数据做判断
      $validate = $this->validation(array('field' => 'id[]', 'label' => 'lang:news_id', 'rules' => 'trim|required|is_natural|xss_clean'));
      if (TRUE !== $validate)
      {
            $result['error']   = TRUE;
            $result['message']   = $validate;
            echo json_encode($result);
            return ;
      }
      
      // 获取文章ID值,并放入数组
      $news_id['id'] = $this->input->post('id');
      if (TRUE === $this->news_m->delete_news($news_id))
      {
            echo json_encode($result);
            return ;
      }
      else
      {
            $result['error']   = TRUE;
            $result['message']   = $this->lang->line('msg_operation_failed');
            echo json_encode($result);
            return ;
      }
    }



Hex 发表于 2013-3-5 13:15:18

常规的方法就是继承。
不过如果是连视图都很像,还需要在结合其他方案。

qiutao520 发表于 2013-3-9 14:47:43

楼主你这个我提个建议……

我们写.NET JAVA的时候。都是这样的一个过程。 VIEW - CONTROLLER - SERVICES - MODEL.你的中间少了一层SERVICES,

我的做法是把SERVICES放在libraries里面
例如:

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class Commentservice {

        var $instance;

        function __construct(){
                $this->instance = & get_instance();
        }

        public function addcomment($memberid, $shopid, $foodid, $content) {
                $this->instance->load->model('comment_model');
                $this->instance->comment_model->memberid = $memberid;
                $this->instance->comment_model->shopid = $shopid;
                $this->instance->comment_model->foodid = $foodid;
                $this->instance->comment_model->content = $content;
                $this->instance->comment_model->rankid = 0;
                $this->instance->comment_model->memberimageid = 0;
                $this->instance->comment_model->addtime = time();
                $this->instance->comment_model->insert();
        }

        public function getlist($shopid, $foodid, $cols = '*', $pn = 0, $rn = 20) {
                $this->instance->load->model('comment_model');
                return $this->instance->comment_model->getlist($shopid, $foodid, $pn, $rn, $cols);
        }
}

而调用的时候。

$this->load->library('commentservice');
$this->commentservice->getlist($shopid, $foodid, $cols, 0, $commrn);

另外你的AJAX消息模型可以抽象出来。做成这样的一个类似的

class Result_model extends CI_Model {
        var $error = "0";
        var $message = "";
        var $data = "";

        function tojson() {
                return json_encode($this);
        }
}

gauspican 发表于 2013-3-10 08:55:23

qiutao520 发表于 2013-3-9 14:47 static/image/common/back.gif
楼主你这个我提个建议……

我们写.NET JAVA的时候。都是这样的一个过程。 VIEW - CONTROLLER - SERVICES - ...

不错

iloveagan 发表于 2013-3-12 14:25:51

qiutao520 发表于 2013-3-9 14:47 static/image/common/back.gif
楼主你这个我提个建议……

我们写.NET JAVA的时候。都是这样的一个过程。 VIEW - CONTROLLER - SERVICES - ...

不错,不错,说的有道理,ajax那个确实可以抽象出来。
没做过java的,所以services这一层不太理解,有空好好研究研究。
非常感谢!

逆天鬼 发表于 2013-5-26 22:14:04

{:soso_e179:} 有实战意义

guowenlong111 发表于 2013-6-11 15:59:09

{:1_1:}

frankth 发表于 2013-8-26 14:35:21

   是可以这样的。java中非常重视分层来实现。services调用model的基本方法,controller调用service来实现。
ci 在设计中,没有把服务层考虑进来,而把主要的业务逻辑处理集中在controller。这样就是lz在使用中带来的困惑。
    不过刚刚“我的做法是把SERVICES放在libraries里面”,我不怎么赞成。毕竟,ci在设计中,把lib库作为扩展库或者第三方库。这样使用对后期使用会产生困惑。建议扩展一个新的文件目录,如service,调用方法:$this->load->service("XXX_service");
页: [1]
查看完整版本: CI控制器相似业务重复问题的疑惑