关于Laravel参数验证的一些疑与惑
验证器怎么创建的,谁创建的
Laravel 文档调用验证器,除了通过控制器,还有就是通过Facades的方式创建验证器对象。Validator::make(data,rule,
config/app.php 中注册了’Validator’ = IlluminateSupportFacadesValidator::class。
<?php
namespace IlluminateSupportFacades;
/**
* @see IlluminateValidationFactory
*/
class Validator extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'validator';
}
}
从上面可以看出,Validator的实际实现类是容器中的validator对象,那这个validator对象是哪个?
<?php
namespace IlluminateFoundation;
...
class Application extends Container implements ApplicationContract, HttpKernelInterface
{
...
public function registerCoreContainerAliases()
{
foreach ([
...
'validator'= [
IlluminateValidationFactory::class,
IlluminateContractsValidationFactory::class
],
])
...
}
...
}
可以看出,最终创建验证器是通过实现IlluminateContractsValidationFactory接口的IlluminateValidationFactory类创建的。再来看看,这个工厂类怎么创建实际的验证器的。
//IlluminateContractsValidationFactory 源码
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
);
}
到这里,可以看出Laravel的验证器的创建都是通过特定的工厂类创建。
如果需要自定义验证器类(比如我需要把5.8的一些新功能迁移到5.5的版本上),有两种方式:
一,创建一个自定义的工厂类。然后在AppServiceProvider中重新绑定新的验证器工厂创建类;
二,AppServiceProvider中通过resolver方法设置工厂类的resolver属性,接管验证器的实例化,例如:
Validator::resolver(function($translator, $data, $rules, $messages, $customAttributes){
return new ExtendValidator($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]))
{
return true;
}
return false;
});
//IlluminateContractsValidationFactory 源码
public function extend($rule, $extension, $message = null)
{
$this- extensions[$rule] = $extension;
if ($message) {
$this- fallbackMessages[Str::snake($rule)] = $message;
}
}
//IlluminateValidationValidator 源码
protected function callExtension($rule, $parameters)
{
$callback = $this- extensions[$rule];
if (is_callable($callback)) {
return call_user_func_array($callback, $parameters);
} elseif (is_string($callback)) {
return $this- callClassBasedExtension($callback, $parameters);
}
}
protected function validateAttribute($attribute, $rule)
{
...
$method = "validate{$rule}";
if ($validatable && ! $this- $method($attribute, $value, $parameters, $this)) {
$this- addFailure($attribute, $rule, $parameters);
}
}
public function __call($method, $parameters)
{
$rule = Str::snake(substr($method, 8));
if (isset($this- extensions[$rule])) {
return $this- callExtension($rule, $parameters);
}
throw new BadMethodCallException(sprintf(
'Method %s::%s does not exist.', static::class, $method
));
}
Factory提供了extend方法用于扩展规则验证方法。所有的扩展规则最终都会被传到验证器中。验证器在验证参数的过程中,如果找到匹配的验证规则,则直接进行验证。否则调用魔术方法__call查找扩展验证函数。扩展函数返回布尔值,返回true则表示验证通过,返回false表示验证失败。
2 通过自定义规则类扩展
Laravel 中提供了IlluminateContractsValidationRule接口,只有实现了这个接口的类都认为是符合的自定义验证规则类。
<?php
namespace IlluminateContractsValidation;
interface Rule
{
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value);
/**
* Get the validation error message.
*
* @return string
*/
public function message();
}
自定义规则类需要实现的方法有passes方法,用于验证参数是否合法。message方法,用于提供验证失败的错误提示信息。
使用自定义验证类,相对于extend方法扩展有一个很大的bug就是无法在自定义类中获取到当期的验证器对象。从而导致在当前扩展的验证规则中,只能过获取到需要验证的数据,而获取不到其他的字段数据,无法进行联合字段的验证。像上面比较两个字段的大小的验证规则就无法实现。
如果想要通过自定义验证规则类实现上面两个字段大小比较的验证规则,则需要自定义验证类,修改validateUsingCustomRule方法,将当期验证器传入到自定义验证规则实例对象中去。
protected function validateUsingCustomRule($attribute, $value, $rule)
{
if(method_exists($rule, 'setValidator'))
{
$rule- setValidator($this);
}
return parent::validateUsingCustomRule($attribute,$value,$rule);
}
如何实现用当期类方法作为验证规则验证函数
像Yii2中,因为基本上所有的对象都有验证方法,所以很容易用当期类方法作为验证规则验证函数。
例如,一个验证规则如下,表示用当期类的validateMinNum对参数进行验证,那么,这样的一个功能,如何在Laravel中实现呢。
['min_num'= 'validateMinNum']
方法1 通过自定义类实现 Laravel提供了ClosureValidationRule自定义验证类,用来添加回调函数的验证。
例如
$rule = [
'min'= new ClosureValidationRule([$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方式进行回调函数的验证。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对ZaLou.Cn的支持。
- Git 进阶指南
- Python 文本挖掘:使用情感词典进行情感分析(算法及程序设计)
- 可能是地球上最好用的 Mac 词典工具
- 经典Java面试题收集
- alert日志中的一条ora警告信息的分析(59天)
- golang 详解defer
- 猫哥网络编程系列:HTTP PEM 万能调试法
- 分析函数牛刀小试 (59天)
- 猫哥网络编程系列:详解 BAT 面试题
- SpringMVC中@RequestBody引起的400异常处理,返回校验失败具体信息
- 关于primary key和unique index的奇怪问题 (58天)
- 在centos7上安装Jenkins
- Spring resource bundle多语言,单引号format异常
- String的内存模型,为什么String被设计成不可变的
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- SimpleCommand框架介绍以及简单使用(一)
- Android开发中使用achartengine绘制各种图表的方法
- Android开发中Listview动态加载数据的方法示例
- Android自定义实现顶部粘性下拉刷新效果
- Android开发使用自定义view实现ListView下拉的视差特效功能
- Android打造炫酷进度条效果
- Android开发实现自定义新闻加载页面功能实例
- Android下Activity间通信序列化过程中的深浅拷贝浅析
- Android升级支持库版本遇到的两个问题详解
- Android开发使用Drawable绘制圆角与圆形图案功能示例
- Android开发中自定义ProgressBar控件的方法示例
- Android 使用自定义RecyclerView控件实现Gallery效果
- Android开发中GridView用法示例
- React Native中Android物理back键按两次返回键即退出应用
- Android仿简书搜索框效果的示例代码