Laravel 验证器 Validation

本文详细介绍了Laravel框架中的表单验证机制,包括快速验证、表单请求验证的创建和授权,以及自定义错误消息和验证属性。同时,讨论了如何在验证过程中添加钩子函数和处理验证失败的情况。此外,还涵盖了手动创建验证器、自定义验证规则和处理错误信息的方法。

1. 快速验证

        1.1 验证错误信息显示

        1.2 重新填写表单

        1.3 非必填字段的注意点

2. 表单请求验证

        2.1 创建表单请求验证(app/Http/Requests)

面对更复杂的情况,你可以创建一个「表单请求」来应对更复杂的验证逻辑。表单请求是一个包含了验证逻辑的自定义请求类。要创建一个表单请求类,请使用 make:request Artisan CLI 命令:

php artisan make:request StorePostRequest

该命令生成的类将被置于 app/Http/Requests 目录中。如果这个目录不存在,在您运行 make:request 命令后将会创建这个目录。Laravel 生成的每个表单请求都有两种方法:authorizerules

你可能已经猜到了,authorize 方法负责确定当前经过身份验证的用户是否可以执行请求操作,而 rules 方法则返回适用于请求数据的验证规则:

/**
 * 获取应用于该请求的验证规则。
 *
 * @return array
 */
public function rules()
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

所以,验证规则是如何运行的呢?你所需要做的就是在控制器方法中类型提示传入的请求。在调用控制器方法之前验证传入的表单请求,这意味着你不需要在控制器中写任何验证逻辑:

/**
 * 存储新的博客文章。
 *
 * @param  \App\Http\Requests\StorePostRequest  $request
 * @return Illuminate\Http\Response
 */
public function store(StorePostRequest $request)
{
    // 传入的请求通过验证...

    // 获取通过验证的数据...
    $validated = $request->validated();
}

如果验证失败,就会生成一个让用户返回到先前的位置的重定向响应。这些错误也会被闪存到 session 中,以便这些错误都可以在页面中显示出来。如果传入的请求是 XHR,会向用户返回具有 422 状态代码和验证错误信息的 JSON 数据的 HTTP 响应。

在表单请求后添加钩子

如果你想在表单请求「之后」添加钩子,可以使用 withValidator 方法。这个方法接收一个完整的验证构造器,允许你在验证结果返回之前调用任何方法:

/**
 * 配置验证实例。
 *
 * @param  \Illuminate\Validation\Validator  $validator
 * @return void
 */
public function withValidator($validator)
{
    $validator->after(function ($validator) {
        if ($this->somethingElseIsInvalid()) {
            $validator->errors()->add('field', 'Something is wrong with this field!');
        }
    });
}

        2.2 表单请求认证授权

表单请求类内也包含了 authorize 方法。在这个方法中,你可以检查经过身份验证的用户确定其是否具有更新给定资源的权限。例如,你可以判断用户是否拥有更新文章评论的权限:最有可能的是,你将通过以下方法与你的 授权与策略 进行交互:

use App\Models\Comment;

/**
 * 确定用户是否有请求权限
 *
 * @return bool
 */
public function authorize()
{
    $comment = Comment::find($this->route('comment'));

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

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

Route::post('/comment/{comment}');

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

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

/**
 * 判断用户是否有请求权限
 *
 * @return bool
 */
public function authorize()
{
    return true;
}

   

    2.3 自定义错误验证信息

你可以通过重写表单请求的 messages 方法来自定义错误消息。此方法应返回属性 / 规则对及其对应错误消息的数组:

/**
 * 获取已定义验证规则的错误消息。
 *
 * @return array
 */
public function messages()
{
    return [
        'title.required' => 'A title is required',
        'body.required' => 'A message is required',
    ];
}

        2.4 自定义验证属性

Laravel 的许多内置验证规则错误消息都包含 :attribute 占位符。如果你希望将验证消息的 :attribute 部分替换为自定义属性名称,则可以重写 attributes 方法来指定自定义名称。此方法应返回属性 / 名称对的数组:

/**
 * 获取验证错误的自定义属性
 *
 * @return array
 */
public function attributes()
{
    return [
        'email' => 'email address',
    ];
}

        2.5 准备验证输入

如果你需要在应用验证规则前清除请求中的任何数据,你可以使用 prepareForValidation 方法:

use Illuminate\Support\Str;

/**
 * 准备验证数据。
 *
 * @return void
 */
protected function prepareForValidation()
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

    

3. 自定义验证器

如果你不想在请求中使用 validate 方法,你可以使用 Validator门面 手动创建一个验证器实例。门面中的 make 方法将会生成一个新的验证器实例:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PostController extends Controller
{
    /**
     * 存储一篇博客文章。
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // 存储博客文章...
    }
}

make 方法中的第一个参数是期望校验的数据。第二个参数是应用到数据上的校验规则。

如果校验失败,你可以使用 withErrors 方法将错误信息闪存至 session 中。使用该方法时,$errors 会自动与之后的视图共享,你可以很方便将其回显给用户。withErrors 方法接受验证器实例,MessageBag 或是 PHP 数组

        3.1 自动重定向

如果你想要在手动创建验证器实例的同时,使用请求的 validate 方法的自动重定向功能,那么你可以在现有的验证器实例上调用 validate 方法。如果校验失败,用户将被自动重定向,或在 XHR 请求下,将会返回一个 JSON 响应:

Validator::make($request->all(), [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
])->validate();

如果校验失败,你可以使用 validateWithBag 方法将错误信息存储到 命名错误包 中。

Validator::make($request->all(), [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
])->validateWithBag('post');

        3.2 命名错误信息包

如果你的一个页面中存在多个表单,你可以为错误的 MessageBag 命名,用于检索指定表单的错误信息。只需将名称作为 withErrors 的第二个参数传递给它:

return redirect('register')->withErrors($validator, 'login');

你可以通过 $errors 变量访问命名后的 MessageBag 实例:

{{ $errors->login->first('email') }}

        3.3 自定义错误信息

如果需要,你可以提供验证程序实例使用的自定义错误消息,而不是 Laravel 提供的默认错误消息。有几种指定自定义消息的方法。首先,你可以将自定义消息作为第三个参数传递给 Validator::make 方法

$validator = Validator::make($input, $rules, $messages = [
    'required' => 'The :attribute field is required.',
]);

在此示例中,:attribute 占位符将被验证中的字段的实际名称替换。你也可以在验证消息中使用其他占位符。例如:

$messages = [
    'same' => 'The :attribute and :other must match.',
    'size' => 'The :attribute must be exactly :size.',
    'between' => 'The :attribute value :input is not between :min - :max.',
    'in' => 'The :attribute must be one of the following types: :values',
];

为给定属性指定自定义消息

有时你可能希望只为特定属性指定自定义错误消息。你可以使用「点」表示法。首先指定属性名称,然后指定规则:

$messages = [
    'email.required' => 'We need to know your email address!',
];

        3.4 验证后的钩子

验证器允许您在完成验证操作后执行附加的回调。以便您处理下一步的验证,甚至是往信息集合中添加更多的错误信息。您可以在验证器实例上使用 after 方法以实现之:

$validator = Validator::make(...);

$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add(
            'field', 'Something is wrong with this field!'
        );
    }
});

if ($validator->fails()) {
    //
}

4. 错误信息处理

通过 Validator 实例调用 errors 方法,它会返回一个 Illuminate\Support\MessageBag 实例,该实例包含了各种可以很方便地处理错误信息的方法。并自动给所有视图提供 $errors 变量,也是 MessageBag 类的一个实例。

检索特定字段的第一个错误信息

你可以使用 first 方法检索给定字段的第一个错误信息:

$errors = $validator->errors();

echo $errors->first('email');

检索特定字段的所有错误信息

你可以使用 get 方法检索给定字段所有信息的数组:

foreach ($errors->get('email') as $message) {
    //
}

如果要验证表单的数组字段,你可以使用 * 字符来获取每一个数组元素的所有错误信息:

foreach ($errors->get('attachments.*') as $message) {
    //
}

检索所有字段的所有错误信息

你可以使用 all 方法获取所有字段的所有错误信息的数组:

foreach ($errors->all() as $message) {
    //
}

判断特定字段是否含有错误信息:

has方法可用于判断给定字段是否包含任何错误信息:

if ($errors->has('email')) {
    //
}

        4.1 在语言文件中指定错误信息

Laravel 的内置验证规则每个都对应一个错误消息,位于应用程序的 resources/lang/en/validation.php 文件中。在此文件中,你将找到每个验证规则的翻译条目。你可以根据应用程序的需求随意更改或修改这些消息。

此外,你可以将此文件复制到另一个翻译语言目录中,以翻译应用程序语言的消息。要了解有关 Laravel 本地化的更多信息,请查看完整的本地化文档

        4.2 指定属性

特定属性的自定义消息

你可以在应用程序的验证语言文件中自定义用于指定属性和规则组合的错误消息。为此,请将消息自定义项添加到应用程序的 resources/lang/xx/validation.php 语言文件的 custom 数组中:

'custom' => [
    'email' => [
        'required' => 'We need to know your email address!',
        'max' => 'Your email address is too long!'
    ],
],

在语言文件中指定属性

Laravel 的许多内置错误消息都包含一个 :attribute: 占位符,该占位符已被验证中的字段或属性的名称替换。如果你希望将验证消息的 :attribute 部分替换为自定义值,则可以在 resources/lang/xx/validation.php 语言文件的 attributes 数组中指定自定义属性名称:

'attributes' => [
    'email' => 'email address',
],

        4.3 指定值

Laravel 的一些内置验证规则错误消息中包含一个 :value 占位符,该占位符被 request 属性的当前值替换。但是,有时你可能需要将验证消息的 :value 部分替换为该值的自定义表示形式。例如,考虑以下规则,该规则指定如果 payment_type 的值为 cc,则要求提供信用卡号:

Validator::make($request->all(), [
    'credit_card_number' => 'required_if:payment_type,cc'
]);

 如果此验证规则失败,将产生以下错误消息:

The credit card number field is required when payment type is cc.

除了显示 cc 作为付款类型的值外,你还可以通过定义 values 数组在 resources/lang/xx/validation.php 语言文件中指定一种对用户更加友好的表示形式:

'values' => [
    'payment_type' => [
        'cc' => 'credit card'
    ],
],

现在,错误消息将会显示如下:

The credit card number field is required when payment type is credit card.

5. 框架默认的验证规则

6. 按条件添加验证规则

        6.1 字段包含特定值跳过验证

如果另一个字段具有给定的值,你可能偶尔希望不验证给定字段。你可以使用 exclude_if 验证规则来实现这一点。在本例中,如果 has_appointment 字段的值为 false ,则不会验证 appointment_date doctor_name 字段

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($data, [
    'has_appointment' => 'required|boolean',
    'appointment_date' => 'exclude_if:has_appointment,false|required|date',
    'doctor_name' => 'exclude_if:has_appointment,false|required|string',
]);

你可以使用 exclude_unless 规则来验证给定字段,除非另一个字段具有给定的值:

$validator = Validator::make($data, [
    'has_appointment' => 'required|boolean',
    'appointment_date' => 'exclude_unless:has_appointment,true|required|date',
    'doctor_name' => 'exclude_unless:has_appointment,true|required|string',
]);

        6.2 存在时则验证

在某些情况下,你可能希望将要验证的字段存在于输入数组中时,才对该字段执行验证。可以在规则列表中增加 sometimes 来实现

$v = Validator::make($request->all(), [
    'email' => 'sometimes|required|email',
]);

在上面的例子中,email 字段只有在 $data 数组中存在时才会被验证。

        6.3 复杂条件验证

有时候你可能需要增加基于更复杂的条件逻辑的验证规则。例如,你可以希望某个指定字段在另一个字段的值超过 100 时才为必填。或者当某个指定字段存在时,另外两个字段才能具有给定的值。增加这样的验证条件并不难。首先,使用静态规则创建一个 Validator 实例:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'email' => 'required|email',
    'games' => 'required|numeric',
]);

假设我们有一个专为游戏收藏家所设计的网页应用程序。如果游戏收藏家收藏超过一百款游戏,我们会希望他们来说明下为什么他们会拥有这么多游戏。比如说他们有可能经营了一家游戏分销商店,或者只是为了享受收集的乐趣。为了在特定条件下加入此验证需求,可以在 Validator 实例中使用 sometimes 方法。

$v->sometimes('reason', 'required|max:500', function ($input) {
    return $input->games >= 100;
});

技巧:传递给 闭包 的 $input 参数是 Illuminate\Support\Fluent 的一个实例,可用于访问输入和文件。

7. 数组验证

验证表单的输入为数组的字段也不再难了。 你可以使用「点」方法来验证数组中的属性。例如, 如果传入的 HTTP 请求中包含 photos[profile] 字段,可以如下验证:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'photos.profile' => 'required|image',
]);

我们还可以验证数组的每个元素。 例如,要验证给定数组输入中每个 email 是否是唯一的,可以这么做:

$validator = Validator::make($request->all(), [
    'person.*.email' => 'email|unique:users',
    'person.*.first_name' => 'required_with:person.*.last_name',
]);

同样,在指定 语言文件中的自定义验证消息 时,你也可以使用 * 字符,将单个验证消息用于基于数组字段的验证规则:

'custom' => [
    'person.*.email' => [
        'unique' => 'Each person must have a unique email address',
    ]
],

8. 自定义验证规则

    8.1 使用规则类

尽管 Laravel 提供了多种多样有用的校验规则;但你亦可进行自定义。注册自定义校验规则的方法之一便是使用规则对象。你可以使用 make:rule 生成新的规则对象。接下来,让我们使用该命令生成一个校验字符串是否是大写的规则, Laravel 会将新规则置于 app/Rules 目录中。如果该目录不存在,则在你执行 Artisan 命令创建规则时,Laravel 将创建该目录:

php artisan make:rule Uppercase

当规则创建成功后,我们便可定义其行为。规则对象包含两个方法:passes 和 message 。passes 方法接收属性值及其名称,它应该返回以 true 和 false 表示的属性值是否通过验证的结果。message 方法应该返回验证失败时使用的错误信息:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Uppercase implements Rule
{
    /**
     * 判断是否通过验证规则。
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return strtoupper($value) === $value;
    }

    /**
     * 获取校验错误信息。
     *
     * @return string
     */
    public function message()
    {
        return 'The :attribute must be uppercase.';
    }
}

如果你想要从你的翻译文件中获取错误信息,你可以在你的 message 中使用 trans 助手方法:

/**
 * 获取校验错误信息。
 *
 * @return string
 */
public function message()
{
    return trans('validation.uppercase');
}

一旦定义了规则,你便可以通过将规则的实例化与其他校验规则一起传递给验证器:

use App\Rules\Uppercase;

$request->validate([
    'name' => ['required', 'string', new Uppercase],
]);

        8.2 使用闭包

如果你的规则在应用中仅仅使用一次,那你便可使用闭包来代替规则对象。闭包函数接收属性的方法,属性的值以及在校验失败时的回调函数 $fail

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'title' => [
        'required',
        'max:255',
        function ($attribute, $value, $fail) {
            if ($value === 'foo') {
                $fail('The '.$attribute.' is invalid.');
            }
        },
    ],
]);

        8.3 隐式规则

默认情况下,当要验证的属性不存在或者包含一个空字符串时,包含自定义扩展的校验规则是不会执行的。例如,unique 规则不会校验空字符串:

use Illuminate\Support\Facades\Validator;

$rules = ['name' => 'unique:users,name'];

$input = ['name' => ''];

Validator::make($input, $rules)->passes(); // true

如果想要实现即使属性为空,规则也要校验,那么就需要暗示该属性是必须的。要创建这样的「隐式」扩展,那么你应该实现 Illuminate\Contracts\Validation\ImplicitRule 接口。这个接口将充当验证器的「标识接口」。因此,除了典型的 Rule 接口所需的方法之外,它不会包含任何你需要实现的方法。

参考自 laravel 官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值