为speedphp最新版添加 仿Yii 的简易版 数据验证 支持不同场景,自定义回调

给个意见或建议吧 

扩展一个Model基类

<?php


class BaseModel extends Model{
    
    use ValidationRules;
    
    public function rules(){} 
    
}


/**
 * 验证参数规则 
 */
trait ValidationRules{
    
    
    public $_data;
    public $errors = []; // 验证产生的错误
    public $scene = 'default'; // 场景 ['update','create']
    private $ok = true;
    
    /**
     * 验证数据
     */
    public function validate($data){
        if($this->errors) $this->errors = [];
        $_rules = $this->rules();
        $this->_data = $data;
        if(!$_rules) return true;
        if(!is_array($_rules)) throw new ErrorException('Model::rules必须为数组');
        foreach($_rules as $key => $val){
            $this->checkRow($val);
        }
        return $this->ok;
    }
    
    public function addErrors($msg){
        $this->errors[] = $msg;
    }
    
    //检查一行
    private function checkRow(&$row){
        if(count($row) < 2 || !is_array($row)) throw new ErrorException('Model::rules格式错误');
        if(isset($row['on']) && is_array($row['on']) && !in_array($this->scene,$row['on'])) return true;  // 如果 on  不是array 或者不是当前的场景 则忽略   如果没定义on 则是公用的 
        if(is_array($row[0])){
            foreach($row[0] as $k => $v){
                $this->checkField($v,$row[1],$row);
            }
        }elseif(is_string($row[0])){
            $this->checkField($row[0],$row[1],$row);
        }else{
            throw new ErrorException('Model::rules格式错误');
        }
    }
    //检查一个字段
    private function checkField($field,&$func,&$row){
        if($func instanceof Closure){
            !$func($field,$row) && $this->ok = false;
        }elseif(is_string($func)){
            if(!method_exists($this,$func))  throw new ErrorException('Model的方法:'.$func.' 不存在');
            if( $func =='required' || (isset($this->_data[$field]) && $this->_data[$field] !='')){
                !$this->$func($field,$row) && $this->ok = false;
            }
        }else{
           throw new ErrorException('Model::rules格式错误'); 
        }
    }
    
    protected function required($field,&$row){  //必须的字段不能为空  其他的类型检查 可以为空(只有当有值且不符合规则的时候才为false)
        if(isset($this->_data[$field])?$this->_data[$field]=='':true){
            $this->addErrors($field.(isset($row['msg'])?$row['msg']:'不能为空'));
            return false;
        }
        return true;
    }
    
    protected function email($field,&$row){
        if(!preg_match( "/^([0-9A-Za-z\-_\.]+)@([0-9a-z]+\.[a-z]{2,3}(\.[a-z]{2})?)$/i", $this->_data[$field])){
            $this->addErrors($field.(isset($row['msg'])?$row['msg']:'格式错误'));
            return false;
        }
        return $this->checkLength($field,$row);
    }
    
    private function checkLength($field,&$row){
        if(isset($row['max'])?mb_strlen($this->_data[$field]) > $row['max']:false){
            $this->addErrors($field."不能超过{$row['max']}个字");
            return false;
        }
        if(isset($row['min'])?mb_strlen($this->_data[$field]) < $row['min']:false){
            $this->addErrors($field."不能少于{$row['min']}个字");
            return false;
        }
        return true;
    }
    
    protected function phone($field,&$row){
        if(!preg_match("/^1[34578]d{9}$/", $this->_data[$field])){ 
            $this->addErrors($field.(isset($row['msg'])?$row['msg']:'格式错误'));
            return false;
        }
        return true;
    }
    
    protected function number($field,&$row){
        if(!preg_match('/^s*[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?s*$/', $this->_data[$field])){
            $this->addErrors($field.(isset($row['msg'])?$row['msg']:'格式错误'));
            return false;
        }
        return $this->checkLength($field,$row);
    }
    
    protected function integer($field,&$row){
        if(!preg_match('/^s*[+-]?d+s*$/', $this->_data[$field])){
            $this->addErrors($field.(isset($row['msg'])?$row['msg']:'格式错误'));
            return false;
        }
        return $this->checkLength($field,$row);
    }
    
    protected function string($field,&$row){
        if (!is_string($this->_data[$field])) {
            $this->addErrors($field.(isset($row['msg'])?$row['msg']:'格式错误'));
            return false;
        }
        return $this->checkLength($field,$row);
    }
    
    protected function files(){
        // 'ext' 'maxSize',max , Multiple
    }
    
    protected function identical($field,&$row){ //一致
        if(!isset($row['field'])) throw new ErrorException('Model::identical必须定义field');
        if ($this->_data[$field] != $this->_data[$row['field']]){
            $this->addErrors($field.(isset($row['msg'])?$row['msg']:"与{$row['field']}不一致"));
            return false;
        }
        return true;
    }
    
}

 model中覆盖rules方法

<?php
class User extends BaseModel{
    
    public $table_name = "user";
    
    
    public function rules(){
        // required email phone number integer string identical
        return [
            [['username','password'],'required'],
            ['password2','required','on'=>['create']],
            ['email','email','msg'=>'邮箱错了','max'=>50],
            ['phone','phone'],
            ['phone','required','on'=>['update']],
            ['score','number'],
            ['tags',function($field,$row){  
                if(!isset($this->_data[$field]) || !is_array($this->_data[$field])){
                    $this->addErrors($field.(isset($row['msg'])?$row['msg']:'格式错误'));
                    return false;
                }
                return true
            }],
            ['age','integer'], 
            [['username','password'],'string','max'=>32,'min'=>6],
            ['password2','identical','field'=>'password'],
        ];

    }
    
    

    
}

Controller中调用

$model = new User();
$model->scene = 'update';
// $a = $model->validate(['username'=>'admin1','password'=>'123456','email'=>'admin@163.com','phone'=>'14526396857','score'=>2.0,'age'=>2,'password2'=>'123456']);
$a = $model->validate([]);
var_dump($a);
print_r($model->errors);