laravel模型自定义验证,同于其它框架(Yii、tp)

laravel在官方文档中有几种验证方式
但是这些方式无法满足,一些逻辑性判断,比如一些特殊验证,需要查询表取数据做对比的

控制器验证
$this->validate($request,[
    'name' => 'required|min:2|max:20',
    'age' => 'required|integer',
    'sex' => 'required|integer',
],[
    'required'=>':attribute 为必填项',
    'min' => ':attribute 长度不符合要求',
    'integer' => ':attribute 必须是一个整形',
],[  'name' => '姓名',
    'age' => '年龄',
    'sex' => '性别',
]);
Validator类验证
$validator = \Validator::make($request->input(),[
    'name' => 'required|min:2|max:20',
    'age' => 'required|integer',
    'sex' => 'required|integer',
],[
    'required'=>':attribute 为必填项',
    'min' => ':attribute 长度不符合要求',
    'integer' => ':attribute 必须是一个整形',
],[  
    'name' => '姓名',
    'age' => '年龄',
    'sex' => '性别',
]);
if($validator->fails()){
    foreach ($validator->errors()->all() as $message) {
        return ['code'=>-1,'msg'=>$message];
    }
}


我追踪源码发现 加上自定义方法后,直接提示找不到这个方法,或者就是直接返回了自定义的错误


错误信息:


(1/1) BadMethodCallException
Method [validateCheckShopPrice] does not exist.

因为我使用的是Validator::make进行验证的我找到了这个类中重要的方法
 

位置 vendor\laravel\framework\src\Illuminate\Validation

protected function resolve(array $data, array $rules, array $messages, array $customAttributes)
{
    if (is_null($this->resolver)) {
        return new Validator($this->translator, $data, $rules, $messages, $customAttributes);
    }
    return call_user_func($this->resolver, $this->translator, $data, $rules, $messages, $customAttributes);
}
跟踪代码会发现走的是new Validator
在相同目录下的文件中 默认会发现他直接初始化了,那么怎么办呢?
public function __construct(Translator $translator, array $data, array $rules, array $messages = [], array $customAttributes = [])
{
    $this->initialRules = $rules;
    $this->translator = $translator;
    $this->customMessages = $messages;
    $this->data = $this->parseData($data);
    $this->customAttributes = $customAttributes;
    $this->setRules($rules);
}

接着往回看,发现在验证完成之后,记性了fails()方法的调用

public function fails()
{
    return ! $this->passes();
}
是不是找到根源了 需要数据是否通过规则
public function passes()
{
    $this->messages = new MessageBag;
    foreach ($this->rules as $attribute => $rules) {
        $attribute = str_replace('\.', '->', $attribute);
        foreach ($rules as $rule) {
            $this->validateAttribute($attribute, $rule);
            if ($this->shouldStopValidating($attribute)) {
                break;
            }
        }
    }
    foreach ($this->after as $after) {
        call_user_func($after);
    }
    return $this->messages->isEmpty();
}

这是真正验证的地方
需要注意
$this->validateAttribute($attribute, $rule);
这是验证规则的地方,我进行了改动
protected function validateAttribute($attribute, $rule)
{
    $this->currentRule = $rule;
    $initialRule = $rule;
    list($rule, $parameters) = ValidationRuleParser::parse($rule);
    if ($rule == '') {
        return;
    }
    if (($keys = $this->getExplicitKeys($attribute)) &&
        $this->dependsOnOtherFields($rule)) {
        $parameters = $this->replaceAsterisksInParameters($parameters, $keys);
    }
    $value = $this->getValue($attribute);
    if ($value instanceof UploadedFile && ! $value->isValid() &&
        $this->hasRule($attribute, array_merge($this->fileRules, $this->implicitRules))
    ) {
        return $this->addFailure($attribute, 'uploaded', []);
    }
    $validatable = $this->isValidatable($rule, $attribute, $value);
    /**
     * 1.自定义方法的前缀都是check
     * 2.写法 check名字:类所在位置 checkShopPrice:\App\Models\Admin\Goods
     * 3.验证如果是字符串就提示错误 我给出的错误提示语均为字符串
     */
    if(substr($initialRule,0,5) == 'check'){
        $initial = array_reverse(explode(':', $initialRule));
        $model = new $initial[0];
        $tipRes = $model->$initial[1]($value, $parameters, $this->data);
        if ($validatable && is_string($tipRes)) {
            $this->addCustomFailure($attribute, $rule, $tipRes);
        }
    }else{
        $method = "validate{$rule}";
        if ($validatable && ! $this->$method($attribute, $value, $parameters, $this)) {
            $this->addFailure($attribute, $rule, $parameters);
        }
    }
}

注释的地方是我加入自定义的代码

报错错误处理我也重新定义了方法,由于原有格式和目前自己写的有出入
protected function addCustomFailure($attribute, $rule, $message)
{
    $this->messages->add($attribute, $message);
    $this->failedRules[$attribute][$rule] = $message;
}

以上代码已经封装好了

使用方法 验证规则
 

public $rule = [
    'shop_price' => ['required', 'checkShopPrice:\App\Models\Admin\Goods'],
];
//错误信息
protected $message = [
    'shop_price.required' => '本店售价必填',
    'shop_price.regex' => '本店售价格式不对',
    'shop_price.checkShopPrice' => '本店售价格式不对',
];
public function checkForm($request){
    try{
        $model = new Goods();
        $validator = Validator::make($request->all(), $model->rule,$model->message);
        if($validator->fails()){
            foreach ($validator->errors()->all() as $message) {
                return ['code'=>-1,'msg'=>$message];
            }
        }
        return ['code'=>1,'msg'=>self::exec_success];
    }catch (ValidationException $e){
        return ['code'=>-1,'msg'=>$e->getMessage()];
    }
}
public static function checkShopPrice($value, $rule, $data){
    if ($value < 0.01) {
        return  '售价不能小于0.01元';
    } else {
        return true;
    }
}

以上是一种情况,就是每一个模型进行自己的验证,还有一种情况就是使用公共函数去做,这样的话 就需要把所有的验证方法做到一个或者多个方法中,就会混乱 不建议这么做
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章