关于Laravel参数验证的一些疑与惑
验证器怎么创建的,谁创建的
Laravel文档调用验证器,除了通过控制器,还有就是通过Facades的方式创建验证器对象。Validator::make($data,$rule,$message)。
config/app.php中注册了'Validator'=>Illuminate\Support\Facades\Validator::class。
从上面可以看出,Validator的实际实现类是容器中的validator对象,那这个validator对象是哪个?
namespaceIlluminate\Foundation; ... classApplicationextendsContainerimplementsApplicationContract,HttpKernelInterface { ... publicfunctionregisterCoreContainerAliases() { foreach([ ... 'validator'=>[ \Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class ], ]) ... } ... }可以看出,最终创建验证器是通过实现\Illuminate\Contracts\Validation\Factory接口的\Illuminate\Validation\Factory类创建的。再来看看,这个工厂类怎么创建实际的验证器的。
//\Illuminate\Contracts\Validation\Factory源码 protectedfunctionresolve(array$data,array$rules,array$messages,array$customAttributes) { if(is_null($this->resolver)){ returnnewValidator( $this->translator, $data, $rules, $messages, $customAttributes ); } returncall_user_func( $this->resolver, $this->translator, $data, $rules, $messages, $customAttributes ); }到这里,可以看出Laravel的验证器的创建都是通过特定的工厂类创建。
如果需要自定义验证器类(比如我需要把5.8的一些新功能迁移到5.5的版本上),有两种方式:
一,创建一个自定义的工厂类。然后在AppServiceProvider中重新绑定新的验证器工厂创建类;
二,AppServiceProvider中通过resolver方法设置工厂类的resolver属性,接管验证器的实例化,例如:
Validator::resolver(function($translator,$data,$rules,$messages,$customAttributes){ returnnewExtendValidator($translator,$data,$rules,$messages,$customAttributes); });如何自定义验证规则
Laravel本身提供了很多通用的参数验证规则,但是对于一些特定的场景,还是需要提供验证规则的扩展。
Laravel验证规则的扩展有两种方式。
1通过extend方法扩展
//这是一个简单的参数比较的验证规则,Laravel5.8中提供,Laravel5.5中未提供 //验证规则如下:'max_num'=>'gte:min', Validator::extend('gte',function($attribute,$value,$parameters,$validator){ if($value>=data_get($validator->getData(),$parameters[0])) { returntrue; } returnfalse; });//\Illuminate\Contracts\Validation\Factory源码 publicfunctionextend($rule,$extension,$message=null) { $this->extensions[$rule]=$extension; if($message){ $this->fallbackMessages[Str::snake($rule)]=$message; } }//\Illuminate\Validation\Validator源码 protectedfunctioncallExtension($rule,$parameters) { $callback=$this->extensions[$rule]; if(is_callable($callback)){ returncall_user_func_array($callback,$parameters); }elseif(is_string($callback)){ return$this->callClassBasedExtension($callback,$parameters); } } protectedfunctionvalidateAttribute($attribute,$rule) { ... $method="validate{$rule}"; if($validatable&&!$this->$method($attribute,$value,$parameters,$this)){ $this->addFailure($attribute,$rule,$parameters); } } publicfunction__call($method,$parameters) { $rule=Str::snake(substr($method,8)); if(isset($this->extensions[$rule])){ return$this->callExtension($rule,$parameters); } thrownewBadMethodCallException(sprintf( 'Method%s::%sdoesnotexist.',static::class,$method )); }Factory提供了extend方法用于扩展规则验证方法。所有的扩展规则最终都会被传到验证器中。验证器在验证参数的过程中,如果找到匹配的验证规则,则直接进行验证。否则调用魔术方法__call查找扩展验证函数。扩展函数返回布尔值,返回true则表示验证通过,返回false表示验证失败。
2通过自定义规则类扩展
Laravel中提供了Illuminate\Contracts\Validation\Rule接口,只有实现了这个接口的类都认为是符合的自定义验证规则类。
自定义规则类需要实现的方法有passes方法,用于验证参数是否合法。message方法,用于提供验证失败的错误提示信息。
使用自定义验证类,相对于extend方法扩展有一个很大的bug就是无法在自定义类中获取到当期的验证器对象。从而导致在当前扩展的验证规则中,只能过获取到需要验证的数据,而获取不到其他的字段数据,无法进行联合字段的验证。像上面比较两个字段的大小的验证规则就无法实现。
如果想要通过自定义验证规则类实现上面两个字段大小比较的验证规则,则需要自定义验证类,修改validateUsingCustomRule方法,将当期验证器传入到自定义验证规则实例对象中去。
protectedfunctionvalidateUsingCustomRule($attribute,$value,$rule) { if(method_exists($rule,'setValidator')) { $rule->setValidator($this); } returnparent::validateUsingCustomRule($attribute,$value,$rule); }如何实现用当期类方法作为验证规则验证函数
像Yii2中,因为基本上所有的对象都有验证方法,所以很容易用当期类方法作为验证规则验证函数。
例如,一个验证规则如下,表示用当期类的validateMinNum对参数进行验证,那么,这样的一个功能,如何在Laravel中实现呢。
['min_num'=>'validateMinNum']方法1通过自定义类实现Laravel提供了ClosureValidationRule自定义验证类,用来添加回调函数的验证。
例如
$rule=[ 'min'=>newClosureValidationRule([$this,'checkv']) ]; $data=['min'=>10]; $v=Validator::make($data,$rule);方法2通过extend方式实现
$rule=[ 'min'=>'checkv' ]; Validator::extend('checkv',[$this,'checkv']);但是这种方式对验证器的影响是全局的。不建议使用。
总结
通过以上源码的学习,可以看出Laravel验证器的创建都是用过验证器工厂类创建的。如果需要自定义验证器,可以通过修改验证器工厂类,或者设置验证器工厂类的resolver属性接管验证器的实例化。
验证规则的扩展有两种方式,一种是通过extend方式实现。extend方式对验证器的影响是全局的,整个运行进程有效。可以获取到验证器本身,因此可以做多个字段关系的验证;另一种是通过自定义规则类实现。自定义规则了只对使用自定义规则类的验证有效。但是自定义规则类本身无法直接获取到验证器本身,不能够做多个字段关系的验证。如果需要实现,则需要使用自定义验证器,将验证器传入到验证规则中去。
Laravel本身提供了ClosureValidationRule的验证规则用于处理回调函数验证规则。同时也可以使用extend方式进行回调函数的验证。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。