关于Laravel参数验证的一些疑与惑

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

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

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

(0)

相关推荐

  • Laravel中unique和exists验证规则的优化详解

    前言 Laravel提供了多种方法来验证应用输入数据.默认情况下,Laravel的控制器基类使用ValidatesRequests trait,该trait提供了便利的方法通过各种功能强大的验证规则来验证输入的HTTP请求. Laravel中通过ValidatesRequests这个trait来验证requests非常的方便,并且在BaseController类中它被自动的引入了. exitsts()和unique()这两个规则非常的强大和便利. 它们在使用的过程中需要对数据库中已有的数据进行验

  • Laravel 5框架学习之表单验证

    在建立一个文章的时候,如果你什么都不输入直接提交,ok,你获得了一个空的文章,没有任何错误提示,这是不对的.在命令行下运行 php artisan 可以看到一个选项 make:request,新建一个form request类.在命令行执行 复制代码 代码如下: php artisan make:request CreateArticleRequest 生成的文件在 app/http/requests 目录下.在文件中我们可以看到两个方法: public function authorize()

  • 在Laravel框架里实现发送邮件实例(邮箱验证)

    在经过一段时间的使用后,发现在项目中很多地方需要用到用户验证,以短信验证和邮箱验证为主流趋势,此篇文章小编给大家总结了如何在Laravel框架中实现发送邮件功能,以后会陆续更上如何实现短信验证..... 在.env文件下 1.配置Laravel文件 MAIL_DRIVER=smtp //建议使用smtp方式 MAIL_HOST=smtp.163.com //建议使用163邮箱 QQ邮箱会有报错 MAIL_PORT=25//smtp 默认为25 MAIL_USERNAME=null //自己的16

  • Laravel4中的Validator验证扩展用法详解

    本文实例讲述了Laravel4中的Validator验证扩展用法.分享给大家供大家参考,具体如下: 不管写接口还是写web页面,实质都是传入参数,然后进行业务逻辑,然后再输出具体内容.所以,对参数的验证是不可避免的一个环节,比如传过来的email是不是为空,是不是合法的email格式?laravel已经为phper想到简化这种逻辑的办法了.就是Validator. Validator的使用 制造一个验证器 validator使用Validator::make可以制造一个验证器.然后使用验证器判断

  • Laravel框架表单验证详解

    基础验证例子 复制代码 代码如下: $validator = Validator::make( array('name' => 'Dayle'), array('name' => 'required|min:5') ); 传递给 make 函数的第一个参数是待验证的数据,第二个参数是对该数据需要应用的验证规则. 多个验证规则可以通过 "|" 字符进行隔开,或者作为数组的一个单独的元素. 通过数组指定验证规则 复制代码 代码如下: $validator = Validator

  • Laravel框架用户登陆身份验证实现方法详解

    本文实例讲述了Laravel框架用户登陆身份验证实现方法.分享给大家供大家参考,具体如下: laravel中检测用户是否登录,有以下的代码: if ( !Auth::guest() ) { return Redirect::to('/dashboard'); } 那Auth::guest是如何调用的呢? laravel用了Facade模式,相关门面类在laravel/framework/src/Illuminate/Support/Facades文件夹定义的,看下Auth类的定义: class

  • Laravel框架实现发送短信验证功能代码

    Laravel框架简介: Laravel是一套简洁.优雅的PHP Web开发框架(PHP Web Framework).它可以让你从面条一样杂乱的代码中解脱出来:它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁.富于表达力. Laravel短信验证思路详解 今天在做到用户注册和个人中心的安全管理时,我实现借助第三方短信平台在Laravel框架中进行手机验证的设置; 由于我做的是一个为客户提供医疗咨询和保健品网站,所以我们对客户个人隐私的保护显得尤为重要,因而在客户登录后进入个人中心前,

  • Laravel5.2使用Captcha生成验证码实现登录(session巨坑)

    最近有朋友要我帮忙弄一下laravel的验证码登陆,所以稍稍研究了一下.(本人都快忘了咋使用laravel了) 首先,安装laravel就不用在下赘述了吧,我的版本是5.2.45(注:laravel5.2.6以上的版本中间件可以自动加载),这还是挺重要的. 安装完成之后,你需要使用composer来加载你的Captcha,具体方法就是在你的composer.json中的require数组中加上"gregwar/captcha":"1.*"这行代码.然后嘞,就在你的项

  • 使用 laravel sms 构建短信验证码发送校验功能

    laravel 实现短信验证码功能,搜索资料发现比较流行的有两个包: 一个是laravel sms 地址  https://github.com/toplan/laravel-sms 一个是easy sms 地址https://github.com/overtrue/easy-sms, 项目中需要实现一个发送和验证短信验证码的功能.以前的办法稍显繁琐.经高人指点,发现可以用 laravel-sms 这个包替代.且配置和使用简单易学.故有了这篇示例. 本例使用了Laravel 5.5. Api S

  • Laravel中使用FormRequest进行表单验证方法及问题汇总

    在`Laravel`中,每一个请求都会被封装为一个`Request`对象,`Form Request`对象就是包含了额外验证逻辑(以及访问权限控制)的自定义`Request`类. 本文分析了FormRequest异常的处理流程并提出了自定义处理FormRequest验证失败的思路. 所有示例基于Laravel 5.1.39 (LTS) 今天天气不错,我们来说说表单验证. Controller中做表单验证 有的同学把表单验证逻辑写在Controller中,例如这个对用户提交评论内容的验证: <?p

随机推荐