问题
$this->validate
是因为所有控制器都使用了 ValidatesRequests
Trait,所以可以使用这个 Trait
中提供的 validate()
方法
那 \App\Http\Requests 里的 validate () 方法是从哪里来的?最终实现是相同的吗?为什么会有两种写法?(我知道Validator::make()
是为了在 控制器外边用)
Laravel 代码如下:
$request->validate()
protected function validateLogin(\App\Http\Requests $request) { $request->validate([ // <---- 看这行 'username' => 'required|string', 'password' => 'required|string', 'captcha' => ['required', 'captcha'], ], [ 'captcha.required' => '验证码不能为空', 'captcha.captcha' => '请输入正确的验证码', ]); }
$this->validate()
public function form(Request $request, $id) { $this->validate($request, [ // <---- 看这行 'title' => 'bail|required|string|between:2,32', 'url' => 'sometimes|url|max:200', 'picture' => 'nullable|string' ]); return response('表单验证通过'); }
解答
我和楼主有一样的问题,于是我去看了下源码
先去 Request 文件
发现只写了几个注释
@method array validate (array $rules, …$params)
并没有相应的方法,去它的父类里看发现也没有
魔法方法__call ()
这种时候就想到了__call () 可以调用非本类中的方法,一找发现还是没有。
很纳闷,用反射类获取 Request 类的所有方法 getMethods (),发现是有__call () 的。
有点懵逼,遂发现 Request 用了几个 Traits,主意查看,发现其中的 Macroable 是有__call () 的
Macroable 的__call ()
那么 $request 调用 validate () 一定是通过这个__call () 的。看看里面写了啥。
发现这个方法非常简单,就是看静态数组 $macros 中是否包含相应方法,有就调用。
那么问题来了,$macros 数组中的方法是哪里来的 laravel 真的好绕
FoundationServiceProvider
Kernel 在进行 handle () 处理请求时,会先进行 bootstrap 阶段,这时会加载 config/app 中的 provider,FoundationServiceProvider 就是其中一个。它在 register () 阶段,执行了 registerRequestValidation () 方法。
registerRequestValidation()
给静态数组 $macros 注册 validate、validateWithBag 方法
源码:
//validator () 是在 helper.php 中
生成一个 ValidationFactory (Illuminate\Contracts\Validation\Factory) 的实例,并将该实例的 validate 方法注册到 $macros 数组中。
但是注意,这个 Illuminate\Contracts\Validation\Factory 是一个接口类,一定在什么地方已经和一个具体类进行了绑定~
注意: 一般框架自带的工具类,都会将简称和相应类名放在别名数组中。知道是为什么吗?
在 Illuminate\Foundation\Application 的构造函数中,有一个 registerCoreContainerAliases () 方法,它里面将一些简称和相应的类名关联起来,放到 aliases 数组和 abstractAliases 数组中
做这些 aliases 数组和 abstractAliases 数组的目的呢,我之前没想明白,现在明白了 就是在遇到像上面要实例化 Illuminate\Contracts\Validation\Factory 接口类时,自动做转换,转换为 validator(而 validator 的绑定会在相应的 provider 中做掉)
结论
再来看看手动生成验证器
Validator::make () 呢其实就是通过 Facade 来操作实例
巧了,也是 validator!说明手动生成验证器和使用 $request->validate () 其实调用的方法是一样的。
最后找找 validator 绑定的具体类
在 config/app 的 providers 中查找,发现是在 Illuminate\Validation\ValidationServiceProvider 中 register () 时绑定了 validator
绑定的类是 Illuminate\Validation\Factory
一开始看 laravel 源码真的很痛苦,不过看多了会发现套路都差不多,努力学习!
转自:https://learnku.com/laravel/t/35039