ThinkPHP3.2.3的一些心得

1.关于模型自动验证和自动完成的心得:
(1)官方文档里验证规则为function的时候,我们可以使用匿名函数来实现文档中调用外部定义好函数的功能,如下:

$validate = array(
            array('goods_id','require','请选择商品',Model::MUST_VALIDATE),
            array('invite_limit','number','邀请好友数量格式错误',Model::MUST_VALIDATE,'regex'),
            array('invite_limit',function($data){
                return intval($data) < 1 ? false : true;
            },'邀请好友数量必须大于0',Model::MUST_VALIDATE,'function')
        );

这样的话,我们就可以不用在外面单独为这个验证规则定义一个专用的函数,也能使代码更简单易读.同理,这个匿名函数同样适用于自动完成的"function"的附加规则
(2)除了验证单个字段,我们还可以组合来验证,比如两个字段比大小,如下:

$validate = array(
            array('goods_id','require','请选择商品',Model::MUST_VALIDATE),
            array('seckill_start','require','请填写秒杀开始时间',Model::MUST_VALIDATE),
            array('seckill_end','require','请填写秒杀结束时间',Model::MUST_VALIDATE),
            array('seckill_start,seckill_end',function($data){
                return strtotime($data['seckill_start']) >= strtotime($data['seckill_end']) ? false : true;
            },'开始时间不能超过结束时间',Model::MUST_VALIDATE,'function'),
        );

这个验证我们可以扒一扒源代码,首先找到核心文件的Model.class.php文件,找到create函数,因为验证需要create去触发,代码如下:

public function create($data='',$type='') {
        // 如果没有传值默认取POST数据
        if(empty($data)) {
            $data   =   I('post.');
        }elseif(is_object($data)){
            $data   =   get_object_vars($data);
        }
        // 验证数据
        if(empty($data) || !is_array($data)) {
            $this->error = L('_DATA_TYPE_INVALID_');
            return false;
        }

        // 状态
        $type = $type?:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT);

        // 检查字段映射
        if(!empty($this->_map)) {
            foreach ($this->_map as $key=>$val){
                if(isset($data[$key])) {
                    $data[$val] =   $data[$key];
                    unset($data[$key]);
                }
            }
        }

        // 检测提交字段的合法性
        if(isset($this->options['field'])) { // $this->field('field1,field2...')->create()
            $fields =   $this->options['field'];
            unset($this->options['field']);
        }elseif($type == self::MODEL_INSERT && isset($this->insertFields)) {
            $fields =   $this->insertFields;
        }elseif($type == self::MODEL_UPDATE && isset($this->updateFields)) {
            $fields =   $this->updateFields;
        }
        if(isset($fields)) {
            if(is_string($fields)) {
                $fields =   explode(',',$fields);
            }
            // 判断令牌验证字段
            if(C('TOKEN_ON'))   $fields[] = C('TOKEN_NAME', null, '__hash__');
            foreach ($data as $key=>$val){
                if(!in_array($key,$fields)) {
                    unset($data[$key]);
                }
            }
        }

        // 数据自动验证
        if(!$this->autoValidation($data,$type)) return false;

        // 表单令牌验证
        if(!$this->autoCheckToken($data)) {
            $this->error = L('_TOKEN_ERROR_');
            return false;
        }

        // 验证完成生成数据对象
        if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据
            $fields =   $this->getDbFields();
            foreach ($data as $key=>$val){
                if(!in_array($key,$fields)) {
                    unset($data[$key]);
                }elseif(MAGIC_QUOTES_GPC && is_string($val)){
                    $data[$key] =   stripslashes($val);
                }
            }
        }

        // 创建完成对数据进行自动处理
        $this->autoOperation($data,$type);
        // 赋值当前数据对象
        $this->data =   $data;
        // 返回创建的数据以供其他调用
        return $data;
     }

通过$this->autoValidation找,一直找到_validationFieldItem函数,代码如下:

/**
     * 根据验证因子验证字段
     * 
     * @access protected
     * @param array $data 创建数据
     * @param array $val 验证因子
     * @return boolean
     */
    protected function _validationFieldItem($data,$val) {
        switch(strtolower(trim($val[4]))) {
            case 'function':// 使用函数进行验证
            case 'callback':// 调用方法进行验证
                $args = isset($val[6])?(array)$val[6]:array();
                if(is_string($val[0]) && strpos($val[0], ','))
                    $val[0] = explode(',', $val[0]);
                if(is_array($val[0])){
                    // 支持多个字段验证
                    foreach($val[0] as $field)
                        $_data[$field] = $data[$field];
                    array_unshift($args, $_data);
                }else{
                    array_unshift($args, $data[$val[0]]);
                }
                if('function'==$val[4]) {
                    return call_user_func_array($val[1], $args);
                }else{
                    return call_user_func_array(array(&$this, $val[1]), $args);
                }
            case 'confirm': // 验证两个字段是否相同
                return $data[$val[0]] == $data[$val[1]];
            case 'unique': // 验证某个值是否唯一
                if(is_string($val[0]) && strpos($val[0],','))
                    $val[0]  =  explode(',',$val[0]);
                $map = array();
                if(is_array($val[0])) {
                    // 支持多个字段验证
                    foreach ($val[0] as $field)
                        $map[$field]   =  $data[$field];
                }else{
                    $map[$val[0]] = $data[$val[0]];
                }
                $pk =   $this->getPk();
                if(!empty($data[$pk]) && is_string($pk)) { // 完善编辑的时候验证唯一
                    $map[$pk] = array('neq',$data[$pk]);
                }
                if($this->where($map)->find())   return false;
                return true;
            default:  // 检查附加规则
                return $this->check($data[$val[0]],$val[1],$val[4]);
        }
    }

分析这段源代码可以知,当验证规则数组的第一个值是数组或者以","相连的字符串,使用function或者callback附加规则时,会将需要验证的数据中的对应的值以一个参数传递给function/匿名函数或者类中的函数,这样的话只要我们按照这个规则去填写验证规则,我们就能实现更为复杂的验证,例如:

array('seckill_start,seckill_end',function($data){
                return strtotime($data['seckill_start']) >= strtotime($data['seckill_end']) ? false : true;
            },'开始时间不能超过结束时间',Model::MUST_VALIDATE,'function'),

你可能感兴趣的:(ThinkPHP3.2.3的一些心得)