Laravel 表单验证:表单验证类
问题
我有一个非常复杂的表单验证场景,写在控制器方法里显得很庞杂臃肿,在 Laravel 中,我可以把验证逻辑单独写在某处么?
回答
对于更复杂的验证场景,Laravel 支持创建一个「表单请求」来处理更为复杂的逻辑。
创建表单请求
表单请求是包含验证逻辑的自定义请求类,我们可以使用 Artisan 命令 make:request
来创建表单请求类:
$ php artisan make:request StoreBlogPost
这会在 app/Http/Requests
目录下创建一个 app\Http\Requests\StoreBlogPost.php
文件,初始内容如下:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreBlogPost extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
可以看到我们的 StoreBlogPost
类继承自 Illuminate\Foundation\Http\FormRequest
类(该类又继承自请求基类 Illuminate\Http\Request
),初始内容中包含两个方法:authorize
和 rules
。
表单请求验证规则
我们创建的 StoreBlogPost
类中的 rules
方法用于返回验证规则数组,比如我们可以添加以下一些验证规则到 rules
方法中:
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
那么验证规则又是如何运行的呢?只要你在控制器方法的参数中类型提示传入的请求,就会在调用控制器方法之前自动验证传入的表单请求,因此就不需要你再在控制器方法中写任何验证逻辑了,下面是某控制器的 store
方法示例:
/**
* 存储传入的博客文章。
*
* @param StoreBlogPost $request
* @return Response
*/
public function store(StoreBlogPost $request)
{
// 传入的请求通过验证...
// 获取通过验证的数据...
$validated = $request->validated();
}
如果验证失败,就会生成一个将用户重定向回先前位置的响应。这些错误也会被闪存到会话中,使得它们可以显示在视图页面中。如果传入的是 AJAX 请求,返回的是具有 422 状态码和验证错误信息的 JSON 类型的 HTTP 响应。
表单请求授权验证
在表单请求类的 authorize
方法中,你可以检查经过身份验证的用户是否具有执行操作所需的权限。比如,你可以判断用户是否拥有更新文章评论的权限:
/**
* 判断用户是否有权限做出此请求。
*
* @return bool
*/
public function authorize()
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
由于所有的表单请求都是继承了 Laravel 中的请求基类 Illuminate\Http\Request
,所以我们可以使用 user
方法去获取当前认证登录的用户。同时请注意上述例子中对 route
方法的调用。这个方法允许你在被调用的路由上获取其定义的 URI 参数,譬如下面例子中的 {comment}
参数:
Route::post('comment/{comment}');
如果 authorize
方法返回 false
,则会自动返回一个包含 403 状态码的 HTTP 响应,也不会运行控制器的方法。
如果你打算在应用程序的其它部分处理授权逻辑,只需从 authorize
方法返回 true
:
/**
* 判断用户是否有权限进行此请求。
*
* @return bool
*/
public function authorize()
{
return true;
}
自定义错误消息
可以重写表单请求的 messages
方法来自定义错误消息。此方法应返回属性 / 规则对及其对应错误消息的数组:
/**
* 获取已定义验证规则的错误消息。
*
* @return array
*/
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
自定义验证属性
如果希望将验证消息的 :attribute
部分替换为自定义属性名称,则可以重写 attributes
方法来指定自定义名称。此方法应返回属性 / 名称对的数组:
/**
* 获取验证错误的自定义属性。
*
* @return array
*/
public function attributes()
{
return [
'email' => 'email address',
];
}
添加表单请求后钩子
我们还可以在表单请求中用 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!');
}
});
}