简介
Laravel 提供了几种方法来验证应用程序的输入数据(incoming data)。默认,Laravel 的基类控制器使用了 validatesRequests
trait。这个 trait 里提供了一种方便验证传入的 HTTP 请求、带有丰富验证规则的方法。
快速上手
要了解 Laravel 强大的验证功能,我们需要看一个完整实例——验证表单,并且显示错误消息给用户。
定义路由
首先,在 routes/web.php
中,包含如下两个路由:
Route::get('posts/create', 'PostsController@create');
Route::post('posts', 'PostsController@store');
GET
路由会给用户显示一个创建博客文章的表单,而 POST
路由用来保存新的博客文章到数据库。
创建控制器
接下里,我们看下处理这些路由的控制器 PostsController
,不过现在 store
方法还是空的:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostsController extends Controller
{
/**
* Show the form to create a new blog post.
*
* @return Response
*/
public function create()
{
return view('posts.create');
}
/**
* Store a new blog post.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// Validate and store the blog post...
}
}
书写验证逻辑
现在,我们在 store
方法里验证提交过来的新博客文章的字段 title
和 body
。我们使用 Illuminate\Http\Request
对象上的 validate
方法。如果字段经过验证规则检验通过,则正常执行后面的代码;如果没通过,一个携带正确错误响应的异常会自动发送给用户。对于传统 HTTP 请求,会生成一个重定向响应;对于 AJAX 请求,会生成一个 JSON 响应。
为了更好理解 validate
方法,我们看下 store
方法内容:
/**
* Store a new blog post.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// The blog post is valid, store in database...
}
我们给 validate
方法传递了期望的验证规则。再一次,如果验证失败,一个 一个携带正确错误信息的响应会自动生成;如果验证成功,我们会继续正常执行后面的代码。
在第一次验证失败时停止
有时,你希望在第一个验证规则失败时,就停止该字段接下来的规则验证。为此,请使用 bail
规则:
$request->validate([
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
在上面的例子里,如果 title
属性的 unique
规则验证失败了,就不再检查 max
规则。这些规则是按照顺序从左到右一个一个验证的。
嵌套属性的验证方式
如果 HTTP 请求中包含「嵌套」参数,你可以使用「点」(.
)语法引用它们:
$request->validate([
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
显示验证错误
如果输入数据字段没有通过验证规则呢?之前提到过,Laravel 会自动重定向到之前的页面,并携带正确的错误信息。另外,这些错误信息是自动 [闪存到会话][1] 中的。
请注意,我们不必在 GET
路由中将错误消息显式绑定到视图。这是因为 Laravel 会自动检查会话数据里的错误消息,并自动将这些错误数据绑定到视图的一个变量 $errors
里。$errors
变量是 Illuminate\Support\MessageBag
实例。
提示!
$errors
这个变量是通过Illuminate\View\Middleware\ShareErrorsFromSession
中间件绑定给视图的。这个中间件包含在了web
中间件组里,因此 所有视图文件里总是会有这个$errors
变量,你无需担心它没有,放心使用吧!
在我们的例子里,当 store
方法里的验证规则失败时,我们就会跳转到创建博客文章的页面,在这里我们可以显示错误消息:
<h1>创建博客文章h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
[@foreach](https://learnku.com/users/5651) ($errors->all() as $error)
<li>{{ $error }}li>
@endforeach
ul>
div>
@endif
验证可选字段
默认,Laravel 项目 App\Http\Kernel
类中定义的全局中间件组里包含 TrimString
和 ConvertEmptyStringsToNull
这两个。而且输入数据字段的 null
值会被验证器看做无效的,如果允许字段为取 null
值,那么加上 nullable
这个验证规则就可以了。
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'published_at' => 'nullable|date',
]);
在这个例子里,我们指定了 published_at
字段可以取 null
值或者是一个有效的日期表示。如果没有加 nullable
这个验证规则,验证器会把 null
看做无效日期。
AJAX 请求 & 验证
对 AJAX 请求使用 validate
方法,Laravel 不会自动生成一个重定向响应,相反,Laravel 会生成一个包含验证错误消息的 JSON 响应。该 JSON 响应将使用 422 HTTP 状态代码发送。
表单请求验证
创建表单请求
对于更加复杂的验证场景,可以使用「表单请求」。何为表单请求?
包含字段验证逻辑的自定义请求类。
实际上,这个表单请求类,并不是只能请求提交的表单字段,还可以处理 AJAX 请求提交过来的字段数据。所以更准确的叫法应该是「包含处理字段验证功能的请求类」,但太长了,是不?
创建一个表单请求类,使用 Artisan 命令 make:request
:
php artisan make:request StoreBlogPost
生成的这个 StoreBlogPost
类,会保存在 app/Http/Requests
目录下。如果目录没有不存在,会在第一次运行 make:request
命令时创建。接下来,我们在 rules
方法里添加一些验证规则:
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
So,这个表单请求类怎么生效呢?你可以在控制器方法里将它作为依赖注入。发起的表单请求会在控制器方法调用前,经表单请求类验证,就是说,你无需在控制器中混杂验证逻辑了:
/**
* Store the incoming blog post.
*
* @param StoreBlogPost $request
* @return Response
*/
public function store(StoreBlogPost $request)
{
// The incoming request is valid...
}
如果验证失败,会自动生成一个重定向响应到之前的地址。错误数据会被闪存进会话,以便在前端显示。如果时 AJAX 请求,Laravel 会返回一个包含验证错误消息的 JSON 响应。该 JSON 响应使用 422 HTTP 状态代码发送。
表单请求的 after
钩子方法……
你可以为表单请求添加一个 after
钩子方法,这是在 withValidator
中定义的。 此方法接收基于当前请求构造的验证器实例对象,让你在实际验证字段之前,调用验证器实例对象的任何方法:
/**
* Configure the validator instance.
*
* @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!');
}
});
}
授权表单请求
表单请求类也可以包含一个 authorize
方法,在此方法内,你可以检查认证用户是否有更新指定资源的权限。例如,你可以判断一个用户是否可以更新指定的博客文章的评论:
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
由于所有的表达请求类继承了 Laravel 基类请求类,我们可以使用 user
方法获得当前认证用户。注意上面调用 route
方法的地方,该方法用来获得路由参数 {comment}
:
Route::post('comments/{comment}');
如果 authorize
方法返回 false
,那么一个携带 403 状态码的 HTTP 响应会自动返回,控制器方法不会执行。
如果你要把认证逻辑放在别处,只要让 authorize
方法直接返回 true
就可以了:
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
自定义错误消息
你可以在表单请求类里使用 messages
方法自定义默认显示的错误消息内容。这个方法返回一个带有键值对的数组,键是「属性.规则」的形式,值是对应规则验证失败时的错误消息内容:
/**
* Get the error messages for the defined validation rules.
*
* @return array
*/
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
手动创建验证器
如果你不用请求实例上的 validate
方法,那么可以使用 Validator
门面手动创建一个验证器。调用门面上的 make
方法,就会生成一个新的验证器实例:
namespace App\Http\Controllers;
use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostsController extends Controller
{
/**
* Store a new blog post.
*
* @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();
}
// Store the blog post...
}
}
传递给 Validator::make
方法的第一个参数是验证数据,第二个参数验证规则。
如果验证失败,你可以使用 withErrors
方法闪存错误消息到会话里。当使用这个方法时,视图里的 $errors
变量会被自动填充数据,以便之后显示。withErrors
方法接收一个验证器实例、MessageBag
或者一个 PHP 数组。
自动跳转
如果你是手动创建验证器,又想在验证失败时,自动跳转的话,请使用验证器实例上的 validate
方法。如果验证失败的话,就能自动跳转了,如果是 AJAX 请求的话,就返回一个 JSON 响应:
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validate();
命名错误包
如果一个页面里包含多个表单,可以为错误 MessageBag
命名。为 withErrors
方法传递第二个参数:
return redirect('register')
->withErrors($validator, 'login');
然后,就可以在 $errors
变量上使用命名的 MessageBag
实例了:
{{ $errors->loogin->first('email') }}
在验证之后的钩子函数
在验证完成之后,可以为验证器添加回调函数。这样,你可以向消息集合里为验证器进一步添加错误消息。这是要使用验证器器上的 after
方法:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
//
}
使用错误消息
在 Validatore
实例上调用 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')) {
//
}
自定义错误消息
如果需要自定义错误消息,这里有几种方法。首先,Validator::make
方法接收的可选第三个参数就是咱们的自定义消息。
$messages = [
'required' => 'The :attribute field is required.',
];
$validator = Validator::make($input, $rules, $messages);
: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 e-mail address!',
];
在语言文件里指定自定义消息
大多数情况下,你可以在语言文件里指定自定义消息,而不是直接传递给 Validator
。为此,在你的语言文件 resources/lang/xx/validation.php
中的 custom
数组里添加自定义消息。
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
在语言文件里指定自定义属性
如果你希望使用自定义属性名称替换验证消息的 :attribute
占位符部分。为此,在你的语言文件 resources/lang/xx/validation.php
中的 attributes
数组里添加自定义属性。
'attributes' => [
'email' => 'email address',
],
本文为转载文章: 原文链接