$request->validate()源码解读
作为一个新手,看laravel官方文档时,总会想去看看源码是怎么实现的。
在看到表单验证那一块时,很好奇Request类调用validate方法与Validator::make()有什么区别?
Validator::make()倒是一下子看懂了,其实这只是调用了个外观类,但$request->validate()就有点看不懂了……
先去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这种外观类是怎么实现的,我这里就不说了,社区里一篇帖子分享一下
博客:深入浅出 Laravel 的 Facade 外观系统
最后找找validator绑定的具体类
在config/app的providers中查找,发现是在Illuminate\Validation\ValidationServiceProvider中register()时绑定了validator
绑定的类是Illuminate\Validation\Factory
一开始看laravel源码真的很痛苦,不过看多了会发现套路都差不多,努力学习!
本作品采用《CC 协议》,转载必须注明作者和本文链接
厉害了!
还想问下,$request->validate()验证后,如果多个参数验证没通过,返回的message会有“(and 1 more error)” 这个额外描述,这个应该怎么优雅地去除呢?
$request->validate() 能自定义验证规则对应的错误提示吗,params 根本不知道该传什么...