作为程序员一定要保持良好的睡眠,才能好编程

laravel 中validate验证规则 利用FormRequest进行数据验证

发布时间:2020-04-03


laravel 中validate验证规则


namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class AddCartRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }
    
    
    //这两种写法都是支持的
    public function rules(){
    
    return [
        'amount' => ['required', 'integer', 'min:1'],
        'pid' => 'required|integer',
    ];
    
    }
    
    
    //如果没有编写message 提示信息,
    //这里的attributes 默认会把 amout 这个字段替换成  商品数量
    //前提是 这条数据没有经过验证
    public function attributes()
        {
            return [
                'amount' => '商品数量'
            ];
        }
        
        public function messages()
        {
            return [
                'sku_id.required' => '请选择商品'
            ];
        }
        
        
        
     
    
}


使用命令行创建验证器

G:\phpstudy\WWW\laravel_base>php artisan make:request UserRequest created successfully.


带有回调函数的验证,有了这条就能做很多的验证了,举例说明,你可以想想看

public function rules()
{
    return [
        'sku_id' => [
            'required',
            function ($attribute, $value, $fail) {
                if (!$sku = ProductSku::find($value)) {
                    return $fail('该商品不存在');
                }
                if (!$sku->product->on_sale) {
                    return $fail('该商品未上架');
                }
                if ($sku->stock === 0) {
                    return $fail('该商品已售完');
                }
                if ($this->input('amount') > 0 && $sku->stock < $this->input('amount')) {
                    return $fail('该商品库存不足');
                }
            },
        ],
        'amount' => ['required', 'integer', 'min:1'],
    ];
}





举例说明一个简单的验证:、

public function rules()
{
    return [
        'reason' => 'required',
        
        // 判断用户提交的地址 ID 是否存在于数据库并且属于当前用户      
        'address_id'     => [
            'required',
            Rule::exists('user_addresses', 'id')->where('user_id', $this->user()->id),
        ],
        
        
    ];
}

public function attributes()
{
    return [
        'reason' => '原因',
    ];
}




使用回调函数,对数组中的数据进行验证

<?php

namespace App\Http\Requests;

use Illuminate\Validation\Rule;
use App\Models\ProductSku;

class OrderRequest extends Request
{
    public function rules()
    {
        return [
            // 判断用户提交的地址 ID 是否存在于数据库并且属于当前用户
            // 后面这个条件非常重要,否则恶意用户可以用不同的地址 ID 不断提交订单来遍历出平台所有用户的收货地址
            'address_id'     => [
                'required',
                Rule::exists('user_addresses', 'id')->where('user_id', $this->user()->id),
            ],
            'items'          => ['required', 'array'],
            'items.*.sku_id' => [ // 检查 items 数组下每一个子数组的 sku_id 参数
                'required',
                function ($attribute, $value, $fail) {
                    if (!$sku = ProductSku::find($value)) {
                        return $fail('该商品不存在');
                    }
                    if (!$sku->product->on_sale) {
                        return $fail('该商品未上架');
                    }
                    if ($sku->stock === 0) {
                        return $fail('该商品已售完');
                    }
                    // 获取当前索引
                    preg_match('/items\.(\d+)\.sku_id/', $attribute, $m);
                    $index = $m[1];
                    // 根据索引找到用户所提交的购买数量
                    $amount = $this->input('items')[$index]['amount'];
                    if ($amount > 0 && $amount > $sku->stock) {
                        return $fail('该商品库存不足');
                    }
                },
            ],
            'items.*.amount' => ['required', 'integer', 'min:1'],
        ];
    }
}




required条件判断

public function rules()
{
    return [
        'agree'  => ['required', 'boolean'],
        'reason' => ['required_if:agree,false'], // 拒绝退款时需要输入拒绝理由
    ];
}






带有attributes的验证

namespace App\Http\Requests;

class UserAddressRequest extends Request
{
    public function rules()
    {
        return [
            'province'      => 'required',
            'city'          => 'required',
            'district'      => 'required',
            'address'       => 'required',
            'zip'           => 'required',
            'contact_name'  => 'required',
            'contact_phone' => 'required',
        ];
    }

    public function attributes()
    {
        return [
            'province'      => '省',
            'city'          => '城市',
            'district'      => '地区',
            'address'       => '详细地址',
            'zip'           => '邮编',
            'contact_name'  => '姓名',
            'contact_phone' => '电话',
        ];
    }
}









 


第一个方法:authorize(),控制用户访问权限


表单请求授权验证

表单请求类内也包含了 authorize 方法。在这个方法中,你可以检查经过身份验证的用户确定其是否具有更新给定资源的权限。比方说,你可以判断用户是否拥有更新文章评论的权限:

/**

 * 判断用户是否有权限做出此请求。

 *

 * @return bool

 */

public function authorize()

{

    $comment = Comment::find($this->route('comment'));


    return $comment && $this->user()->can('update', $comment);

}

由于所有的表单请求都是继承了 Laravel 中的请求基类,所以我们可以使用 user 方法去获取当前认证登录的用户。同时请注意上述例子中对 route 方法的调用。这个方法允许你在被调用的路由上获取其定义的 URI 参数,譬如下面例子中的 {comment} 参数:

如果 authorize 方法返回 false,则会自动返回一个包含 403 状态码的 HTTP 响应,也不会运行控制器的方法。

如果你打算在应用程序的其它部分处理授权逻辑,只需从 authorize 方法返回 true:

/**

 * 判断用户是否有权限进行此请求。

 *

 * @return bool

 */

public function authorize()

{

    return true;

}




第二个方法:$rules(),返回验证的数组

第三个方法:$message(),返回自定义的错误信息




原来控制器写法:

 

传统上我们这样使用,但是造成每个controller都需要对这些参数单独判断.代码复用率不高.


 public function navSet(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'h5_id' => 'required |int',
            'font_color'=>'string|nullable',
            'select_color'=>'string|nullable',
            'background_color'=>'string|nullable',
            'position'=>'int|required| between:0,1'
        ]);
        if ($validator->fails()) {
            return $this->output(null,'参数有误,请重试!',500);
        }
        $request_params=$request->all();
 
     //接下来实现你的业务逻辑....
}



当我们抽离出来参数验证层的时候,


 public function navSet(NavRequest $request)//将你抽离的参数层绑定到这里
    {
          $request_params=$request->all();
       
         //接下来处理你的业务逻辑...
    }

这样不管你在哪里绑定Navrequest这个参数验证类的时候,都会对参数进行验证



验证错误信息的返回

在这个地方我是写接口的,无论如何都接收不到错误信息.然后查看FoemRequest的错误返回信息:


看到这里这样写:如下图.


protected function failedValidation(Validator $validator)
    {
 
        throw (new ValidationException($validator))
                    ->errorBag($this->errorBag)
                    ->redirectTo($this->getRedirectUrl());
    } 
    public function rules(){
        return [
            'account'=>[
                'required',
                'regex:/^1[34578][0-9]\d{4,8}|(\w)+(\.\w+)*@(\w)+((\.\w+)+)|[0-9a-zA-Z_]+$/',//验证为手机号,邮箱,或帐号
            ],
            'password'=>'required|between:6,18',//验证密码
        ];
    }
    public function messages(){
        return [
            'account.required' => '帐号不能为空',
            'account.regex' => '帐号不合法',
            'password.required'  => '密码不能为空',
            'password.between'  => '密码错误',
        ];
    }





看一看图文教程:


1、首先创建验证器

image.png

image.png

如果是false ,则禁止访问,也不会运行controller,且会返回一个http 403 的状态码


http://127.0.0.1:8888/user/index

image.png


User.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;

class User extends FormRequest {
  /**
   * Determine if the user is authorized to make this request.
   *
   * @return bool
   */
  public function authorize() {
    return TRUE;
  }

  /**
   * Get the validation rules that apply to the request.
   *
   * @return array
   */
  public function rules() {
    return [
      'id' => 'required|int'
    ];
  }




  protected function failedValidation(Validator $validator) {

    //echo '1111111111';
    var_dump($validator->getMessageBag());

    exit;


  /*  throw (new ValidationException($validator))
      ->errorBag($this->errorBag)
      ->redirectTo($this->getRedirectUrl());*/
  }
}



验证规则中,正则的写法:

class User extends FormRequest {
  /**
   * Determine if the user is authorized to make this request.
   *
   * @return bool
   */
  public function authorize() {
    return TRUE;
  }

  /**
   * Get the validation rules that apply to the request.
   *
   * @return array
   */
  public function rules() {
    return [
      'id' => 'required|int',
      'phone'=>[
        'required',
        'regex:/^1\d{10}$/'
        //'regex:/^1[34578][0-9]\d{4,8}|(\w)+(\.\w+)*@(\w)+((\.\w+)+)|[0-9a-zA-Z_]+$/'
      ]
    ];
  }

  public function attributes() {

    return [
      'phone'=>'手机号'
    ];
  }
  public function messages() {

    return [
      'phone.required'=>'手机号不能为空',
      'phone.regex'=>'手机号不正确',
    ];

  }

  protected function failedValidation(Validator $validator) {

    //echo '1111111111';
    var_dump($validator->getMessageBag());

    exit;


  /*  throw (new ValidationException($validator))
      ->errorBag($this->errorBag)
      ->redirectTo($this->getRedirectUrl());*/
  }
}

image.png


image.png



public function rules() {
  return [
    'id' => 'required|int',
    'phone' => [
      'required',
      'regex:/^1\d{10}$/'
      //'regex:/^1[34578][0-9]\d{4,8}|(\w)+(\.\w+)*@(\w)+((\.\w+)+)|[0-9a-zA-Z_]+$/'
    ],
    'age' => [
      'required',
      'int',
      function ($attribute, $value, $fail) {

        //这里可以做逻辑验证 注意 在这里  $attribute 是属性名,且不能和messages中的值别名替换。
        if($value<10 || $value>100 ){
          return $fail($attribute.'不能小于10岁且不能大于100');
        }

      }
    ]
  ];
}

public function attributes() {

  return [
    'phone' => '手机号',
    'age' =>'年龄'
  ];
}

public function messages() {

  return [
    'phone.required' => '手机号不能为空',
    'phone.regex' => '手机号不正确',
  ];

}

image.png

image.png








昨日验证通过 这里的方法重写,得到pathinfo上的值,就可以实现路由验证

/**
 * Create the default validator instance.
 *
 * @param  \Illuminate\Contracts\Validation\Factory  $factory
 * @return \Illuminate\Contracts\Validation\Validator
 */
protected function createDefaultValidator(ValidationFactory $factory)
{

  $data=array_merge($this->route()->parameters(),$this->validationData());
  //echo "<pre style='color:blue;font-size:16px;'>";
  //echo __FILE__."  ".__LINE__."<br>";
  //dd($pid);
  //echo "</pre>";
  //exit;
  //   dd($this->validationData());
    return $factory->make(
      $data, $this->container->call([$this, 'rules']),
        $this->messages(), $this->attributes()
    );
}



建议重写这个方法,


/**
 * Get data to be validated from the request.
 *
 * @return array
 */
protected function validationData()
{
    return $this->all();
    
    return array_merge($this->route()->parameters(),$this->all()); 这样既可实现pathinfo上的值验证, 这是有顺序的,为了和 laravel的取值保持一致,先 get、post然后才pathinfo
    
    
}


validator 扩展:

$this->app['validator']->extend('captcha', function ($attribute, $value, $parameters) {
    return captcha_check($value);
});

// Validator extensions
$this->app['validator']->extend('captcha_api', function ($attribute, $value, $parameters) {
    return captcha_api_check($value, $parameters[0]);
});







$rules = [
    'result' => 'sometimes|integer|in:1,2',
    'deviceSource' => 'sometimes|integer|in:' . implode(',', array_filter(SourceEnum::keys())),
    'startTime' => 'sometimes|date',
    'endTime' => 'sometimes|date|after:startTime'
];
$customAttributes = [
    'result' => '结果',
    'deviceSource' => '检测设备',
    'startTime' => '起始时间',
    'endTime' => '截止时间'
];









官方文档:https://learnku.com/docs/laravel/7.x/validation/7467#rule-required-unless