素材牛VIP会员
thinkphp 代码复用的问题
 雪***月  分类:ThinkPHP  人气:868  回帖:2  发布于6年前 收藏

用ThinkPhp3.2做开发,因为很多时候要用到增删改查操作,为了增加代码的复用。我在common中写了一个curdControler和curdModel做代码的增删改查,需要用到增删改查时直接继承curdController和curdModel。

现在有一个问题一般curd操作都要做权限的判断,否则会很危险。我这里的思路是在curdController构造方法中调用一个checkAuth();因为各种功能,权限控制的方法会有不同,怎么强制继承curdController的子类必须重载checkAuth方法了?

我的想法是,我把权限判断函数 定义为抽象方法

protected abstract function checkAuth()

类curdController定义为抽象类,但是抽象类不能被实例化那么构造函数的代码是不是就无效了,这样实现有什么不妥

第二问题,大家在做tp的代码重用时,有什么更好的思路,我这种做法有什么隐患和问题了,谢谢指教.

class CurdController extends Controller
{
    //基础curd类必须进行权限判断,否则会造成很大的问题
    public function __construct()
    {
        parent::__construct();
        $this->checkAuth();
    }

    //存储模型对象
    protected  $_model;
    //权限判断函数
    protected function checkAuth(){}
    //列表处理函数
    public function listC(){
//      列表前置函数
        $this->beforeList();
        $data=$this->_model->lists();
        $this->assign('lists',$data);
        $this->display();
    }

    public function delC(){
        $id=intval(I('get.id'));
        $where['id']=$id;
        $res=$this->_model->del($where);
        $this->redirectUrl($res,'listC');
    }

    public function addC(){
//        添加前置函数
        $this->beforeAdd();
        if(IS_POST){
            $data=I('post.');
            $res=$this->_model->Store($data);
            $this->redirectUrl($res,'listC');
        }
        $this->display();
    }

    public function editC(){
        $id=intval(I('get.id'));
        //where的数组形式
        $where['id']=$id;
//        编辑前置函数
        $this->beforeEdit($where);
        if(IS_POST){
            $where=I('post.');
            $where['id']=$id;
            $res=$this->_model->Store($where);
            $this->redirectUrl($res,'listC');
        }
        $this->display();
    }
    //列表前置操作
    protected function beforeList(){

    }
    /**
     * 添加控制器前置操作
     */
    protected function beforeAdd(){

    }

    /**
     * 编辑控制器前置操作
     * @param $where
     */
    protected function beforeEdit($where){

    }

讨论这个帖子(2)垃圾回帖将一律封号处理……

Lv5 码农
ah***xr 软件测试工程师 6年前#1

代码复用,我建议用PHP的特性:
http://php.net/manual/zh/lang...
或者用闭包绑定(不太推荐):
http://php.net/manual/en/clos...

checkAuth可以通过不同的业务,书写不同的traits,在具体继承curdController的类中使用对应的traits,由于checkAuth()只返回校验结果的真假,所以这个可以向任意的Controller中定制checkAuth()

针对你的第一个问题,由于你在继承了抽象类curdController的子类构造函数里,手动调用了parent::__construct();,只要子类被实例化,父类的构造函数也是可以用的,看下面例子:
代码:

<?php
abstract class A
{
    public function __construct()
    {
        echo '父类';
    }
}

class B extends A
{
    public function __construct()
    {
        parent::__construct();
        echo '子类';
    }
}

$test = new B();

结果:

针对你第二个问题,个人觉得整个结构框架有些粗,对于常见的一对多和多对多关系仍然需要手动去做,建议将这种关联操作也封装起来。

虽然我个人用的比较多的框架是CodeIgniter,但是我觉得MVC(HMVC)模型基本思路都是一致的,所以下面谈下我个人在CodeIgniter里做的重用封装:

我个人将数据表的原子操作放在了底层Model上面(是基于CI-Base-Model改的,你可以看一下CI-Base-Model里的has_manybelongs_to配置),另外我继承了CI-Base-Model自己写了一个CRUD_Model,这个CRUD_Model中,几乎靠一些配置项和一些重写,就可以快速生成一个标准CRUD数组,下面可以放出部分源码:

<?php
/**
 * @uses array_helper
 */
class CRUD_Model extends CI_Base_Model
{
    public $ci;

    public $crud_total = 0;

    private $crud_offset = 0;
    private $crud_page   = 0;
    private $crud_limit  = 20;

    protected $crud_mask = [];

    public $crud_id         = [];
    public $crud_user_id    = 0;
    public $crud_time       = 0;
    public $crud_time_str   = '';
    public $crud_error_code = 0;
    public $crud_has_error  = FALSE;

    public function __construct()
    {
        parent::__construct();
        $this->ci = &get_instance();
    }

    /**
     * ---------------------------------------------------------
     * CRUD Block-separated Methods
     * CRUD 子功能方法
     * ---------------------------------------------------------
     */
    public function crud_paginator($offset = NULL, $page = NULL, $limit = 20)
    {
        // 解析分页参数的方法
        ...
    }

    public function crud_set_error($error_code = 0)
    {
        // 设置错误码(用于API或者Controller判定)和错误标记的方法
        $this->crud_has_error  = TRUE;
        $this->crud_error_code = $error_code;
    }

    protected function crud_process_id($id = 0, $data = [])
    {
        // 处理ID并缓存的方法
        ...
    }

    protected function crud_prepare($data = [])
    {
        // 准备数据(时间戳之类后面需要用到但和主体关系不大的数据)的方法
        $this->crud_time     = time();
        $this->crud_time_str = date('Y-m-d H:i:s', $this->crud_time);
    }

    protected function crud_filter_fields($data = [])
    {
        // 添加和修改时,过滤原数据中不需要的字段的方法
        ...
    }

    protected function crud_save_total($data = [])
    {
        // 查询加上过滤条件后的总条数的方法
        $this->select("''");
        $this->crud_total = $this->count_all_results();
    }

    protected function crud_add_list_filter($data = [])
    {
        // 列表筛选条件过滤方法
    }

    protected function crud_add_detail_filter($data = [])
    {
        // 详情筛选条件过滤方法
    }

    protected function crud_add_fields($data = [])
    {
        // 列表和详情字段附加方法(SELECT子句)
    }

    protected function crud_add_limit()
    {
        // 条数限制(分页过滤器)方法
        if($this->crud_limit !== 'all') {
            $this->limit($this->crud_limit, $this->crud_offset);
        }
    }

    protected function crud_add_order($data = [])
    {
        // 排序附加方法
    }

    protected function crud_add_list_with($data = [])
    {
        // 列表with(CI-Base-Model中额外添加数据的绑定钩子)的附加方法
    }

    protected function crud_add_detail_with($data = [])
    {
        // 详情with的附加方法
    }

    protected function crud_build_item($item = [])
    {
        // 对列表和详情字段进行处理的方法(直接取出来默认是字符串,如果是数字型需要手动转)
        return $item;
    }

    protected function crud_build_proto($data = [])
    {
        // 构造列表分页输出结构的方法,这个之后会向这个数组再附加列表list值
        $proto = [];
        $proto['total']  = ...;
        $proto['offset'] = ...;
        $proto['page']   = ...;
        $proto['is_last_page'] = ...;
        $proto['is_full_page'] = ...;

        return $proto;
    }

    protected function crud_detail_precheck($detail = [])
    {
        // 详情预检查方法
        return TRUE;
    }

    protected function crud_detail_postcheck($detail = [])
    {
        // 详情后期检查方法
        return TRUE;
    }

    protected function crud_insert_precheck($data = [])
    {
        // 新增预检查方法
        return TRUE;
    }

    protected function crud_insert_postcheck($data = [])
    {
        // 新增后期检查方法
        return TRUE;
    }

    protected function crud_update_precheck($data = [])
    {
        // 更新预检查方法
        return TRUE;
    }

    protected function crud_update_postcheck($data = [])
    {
        // 更新后期检查方法
        return TRUE;
    }

    protected function crud_delete_precheck($data = [])
    {
        // 删除预检查方法
        return TRUE;
    }

    protected function crud_delete_postcheck($data = [])
    {
        // 删除后期检查方法
        return TRUE;
    }

    protected function crud_insert_rebuild($data = [])
    {
        // 新增数据时重新构造传入数据的方法(使其符合数据库结构)
        return [];
    }

    protected function crud_update_rebuild($data = [])
    {
        // 更新数据时重新构造传入数据的方法
        return [];
    }

    /**
     * ---------------------------------------------------------
     * CRUD Main Methods
     * CRUD 主要函数
     * ---------------------------------------------------------
     */
    protected function crud_list($offset = NULL, $page = NULL, $limit = 20, $data = [])
    {
        // 查询列表
        ...
    }

    protected function crud_detail($id = 0, $data = [])
    {
        // 查询详情
        ...
    }

    protected function crud_insert($data = [])
    {
        // 添加
        ...
    }

    protected function update_feed($id = 0, $data = [])
    {
        // 修改
        ...
    }

    protected function crud_delete($id = 0)
    {
        // 删除
        ...
    }
}

我这个模型的思路希望可以对你细化CRUD逻辑有所帮助。

Lv5 码农
Y2***Y2 JS工程师 6年前#2
  1. 继承model,基本帮你实现增删改查。

  2. 权限检查属于AOP,在TP中使用HOOK提取出来。

 文明上网,理性发言!   😉 阿里云幸运券,戳我领取