验证器怎么创建的,谁创建的

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方式进行回调函数的验证。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对Devmax的支持。

关于Laravel参数验证的一些疑与惑的更多相关文章

  1. AngularJS下$http服务Post方法传递json参数的实例

    下面小编就为大家分享一篇AngularJS下$http服务Post方法传递json参数的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  2. Laravel自动生成UUID,从建表到使用详解

    今天小编就为大家分享一篇Laravel自动生成UUID,从建表到使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  3. laravel框架模型中非静态方法也能静态调用的原理分析

    这篇文章主要介绍了laravel框架模型中非静态方法也能静态调用的原理,结合实例形式分析了laravel模型基类中使用魔术方法实现非静态方法进行静态调用的相关原理,需要的朋友可以参考下

  4. Laravel相关的一些故障解决

    这篇文章主要给大家介绍了关于Laravel相关的一些故障的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者使用Laravel具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

  5. 解决ajax返回验证的时候总是弹出error错误的方法

    这篇文章主要介绍了解决ajax返回验证的时候总是弹出error错误的方法,感兴趣的小伙伴们可以参考一下

  6. 微信小程序实现手机号码验证

    这篇文章主要为大家详细介绍了微信小程序实现手机号码验证,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  7. Laravel框架中缓存的使用方法分析

    这篇文章主要介绍了Laravel框架中缓存的使用方法,结合具体实例形式分析了Laravel框架中缓存的常用方法、操作步骤及相关使用操作技巧,需要的朋友可以参考下

  8. laravel 实现设置时区的简单方法

    今天小编就为大家分享一篇laravel 实现设置时区的简单方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  9. php检查函数必传参数是否存在的实例详解

    这篇文章主要介绍了php检查函数必传参数是否存在的实例详解的相关资料,需要的朋友可以参考下

  10. laravel框架学习记录之表单操作详解

    这篇文章主要介绍了laravel框架学习记录之表单操作,结合实例形式详细分析了laravel框架表单操作相关的路由请求、视图、资源、渲染、表单验证、错误记录等实现方法与操作注意事项,需要的朋友可以参考下

随机推荐

  1. PHP个人网站架设连环讲(一)

    先下一个OmnihttpdProffesinalV2.06,装上就有PHP4beta3可以用了。PHP4给我们带来一个简单的方法,就是使用SESSION(会话)级变量。但是如果不是PHP4又该怎么办?我们可以假设某人在15分钟以内对你的网页的请求都不属于一个新的人次,这样你可以做个计数的过程存在INC里,在每一个页面引用,访客第一次进入时将访问时间送到cookie里。以后每个页面被访问时都检查cookie上次访问时间值。

  2. PHP函数学习之PHP函数点评

    PHP函数使用说明,应用举例,精简点评,希望对您学习php有所帮助

  3. ecshop2.7.3 在php5.4下的各种错误问题处理

    将方法内的函数,分拆为2个部分。这个和gd库没有一点关系,是ecshop程序的问题。会出现这种问题,不外乎就是当前会员的session或者程序对cookie的处理存在漏洞。进过本地测试,includes\modules\integrates\ecshop.php这个整合自身会员的类中没有重写integrate.php中的check_cookie()方法导致,验证cookie时返回的username为空,丢失了登录状态,在ecshop.php中重写了此方法就可以了。把他加到ecshop.php的最后面去就可

  4. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  5. PHP使用JpGraph绘制折线图操作示例【附源码下载】

    这篇文章主要介绍了PHP使用JpGraph绘制折线图操作,结合实例形式分析了php使用JpGraph的相关操作技巧与注意事项,并附带源码供读者下载参考,需要的朋友可以参考下

  6. zen_cart实现支付前生成订单的方法

    这篇文章主要介绍了zen_cart实现支付前生成订单的方法,结合实例形式详细分析了zen_cart支付前生成订单的具体步骤与相关实现技巧,需要的朋友可以参考下

  7. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  8. PHP+jquery+CSS制作头像登录窗(仿QQ登陆)

    本篇文章介绍了PHP结合jQ和CSS制作头像登录窗(仿QQ登陆),实现了类似QQ的登陆界面,很有参考价值,有需要的朋友可以了解一下。

  9. 基于win2003虚拟机中apache服务器的访问

    下面小编就为大家带来一篇基于win2003虚拟机中apache服务器的访问。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. Yii2中组件的注册与创建方法

    这篇文章主要介绍了Yii2之组件的注册与创建的实现方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

返回
顶部