驗證器怎么創建的,誰創建的
Laravel 文檔調用驗證器,除了通過控制器,還有就是通過Facades的方式創建驗證器對象。Validator::make($data,$rule,$message)。
config/app.php 中注冊了'Validator' => Illuminate\Support\Facades\Validator::class。
?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Validation\Factory
*/
class Validator extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'validator';
}
}
從上面可以看出,Validator的實際實現類是容器中的validator對象,那這個validator對象是哪個?
?php
namespace Illuminate\Foundation;
...
class Application extends Container implements ApplicationContract, HttpKernelInterface
{
...
public function registerCoreContainerAliases()
{
foreach ([
...
'validator'=> [
\Illuminate\Validation\Factory::class,
\Illuminate\Contracts\Validation\Factory::class
],
])
...
}
...
}
可以看出,最終創建驗證器是通過實現\Illuminate\Contracts\Validation\Factory接口的\Illuminate\Validation\Factory類創建的。再來看看,這個工廠類怎么創建實際的驗證器的。
//\Illuminate\Contracts\Validation\Factory 源碼
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;
});
//\Illuminate\Contracts\Validation\Factory 源碼
public function extend($rule, $extension, $message = null)
{
$this->extensions[$rule] = $extension;
if ($message) {
$this->fallbackMessages[Str::snake($rule)] = $message;
}
}
//\Illuminate\Validation\Validator 源碼
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 中提供了Illuminate\Contracts\Validation\Rule接口,只有實現了這個接口的類都認為是符合的自定義驗證規則類。
?php
namespace Illuminate\Contracts\Validation;
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方式進行回調函數的驗證。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。
您可能感興趣的文章:- Laravel框架表單驗證詳解
- Laravel中使用FormRequest進行表單驗證方法及問題匯總
- 在Laravel框架里實現發送郵件實例(郵箱驗證)
- Laravel框架實現發送短信驗證功能代碼
- Laravel 5框架學習之表單驗證
- Laravel4中的Validator驗證擴展用法詳解
- 使用 laravel sms 構建短信驗證碼發送校驗功能
- Laravel中unique和exists驗證規則的優化詳解
- Laravel框架用戶登陸身份驗證實現方法詳解
- Laravel5.2使用Captcha生成驗證碼實現登錄(session巨坑)