表单请求 #
一、表单请求概述 #
1.1 什么是表单请求 #
表单请求(Form Request)是Laravel提供的一种验证机制,将验证逻辑从控制器分离到独立的请求类中。
text
表单请求优势
├── 关注点分离
│ └── 验证逻辑独立
├── 可复用
│ └── 多个控制器共享
├── 自动验证
│ └── 控制器执行前验证
└── 自动重定向
└── 验证失败自动返回
1.2 创建表单请求 #
bash
php artisan make:request StoreUserRequest
生成的文件位于 app/Http/Requests/StoreUserRequest.php。
二、表单请求结构 #
2.1 基本结构 #
php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreUserRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
];
}
}
2.2 authorize方法 #
用于授权检查,返回 true 表示允许请求继续:
php
public function authorize()
{
// 只有管理员可以创建用户
return $this->user()->isAdmin();
// 检查资源所有权
return $this->user()->can('update', $this->post);
// 始终允许
return true;
}
2.3 rules方法 #
定义验证规则:
php
public function rules()
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|min:8|confirmed',
'role' => 'required|in:admin,editor,user',
];
}
三、使用表单请求 #
3.1 在控制器中使用 #
php
use App\Http\Requests\StoreUserRequest;
class UserController extends Controller
{
public function store(StoreUserRequest $request)
{
// 验证已通过,可以安全使用数据
$user = User::create($request->validated());
return redirect()->route('users.show', $user);
}
}
3.2 获取验证数据 #
php
public function store(StoreUserRequest $request)
{
// 获取所有验证通过的数据
$validated = $request->validated();
// 获取部分验证通过的数据
$partial = $request->safe()->only(['name', 'email']);
// 排除某些字段
$partial = $request->safe()->except(['password']);
// 获取所有安全数据
$all = $request->safe()->all();
}
四、自定义错误消息 #
4.1 messages方法 #
php
public function messages()
{
return [
'name.required' => '姓名不能为空',
'email.required' => '邮箱不能为空',
'email.email' => '邮箱格式不正确',
'email.unique' => '该邮箱已被注册',
'password.min' => '密码至少8个字符',
];
}
4.2 attributes方法 #
php
public function attributes()
{
return [
'name' => '姓名',
'email' => '邮箱',
'password' => '密码',
];
}
五、条件验证 #
5.1 根据场景区分规则 #
php
public function rules()
{
$rules = [
'name' => 'required|string|max:255',
'email' => 'required|email',
];
// 创建时邮箱必须唯一
if ($this->isMethod('POST')) {
$rules['email'] .= '|unique:users';
}
// 更新时排除当前用户
if ($this->isMethod('PUT') || $this->isMethod('PATCH')) {
$rules['email'] .= '|unique:users,email,' . $this->user->id;
}
return $rules;
}
5.2 根据路由参数区分 #
php
public function rules()
{
$userId = $this->route('user');
return [
'email' => 'required|email|unique:users,email,' . $userId,
];
}
5.3 根据用户角色区分 #
php
public function rules()
{
$rules = [
'name' => 'required|string|max:255',
];
if ($this->user()->isAdmin()) {
$rules['role'] = 'required|in:admin,editor,user';
}
return $rules;
}
六、准备输入 #
6.1 prepareForValidation方法 #
在验证前修改输入数据:
php
protected function prepareForValidation()
{
// 添加字段
$this->merge([
'slug' => Str::slug($this->title),
]);
// 格式化字段
$this->merge([
'phone' => preg_replace('/[^0-9]/', '', $this->phone),
]);
// 转换布尔值
$this->merge([
'is_active' => $this->boolean('is_active'),
]);
}
6.2 passedValidation方法 #
验证通过后执行:
php
protected function passedValidation()
{
$this->merge([
'password' => bcrypt($this->password),
]);
}
七、验证后钩子 #
7.1 withValidator方法 #
添加验证后逻辑:
php
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseInvalid()) {
$validator->errors()->add('field', '额外验证失败');
}
});
}
7.2 自定义验证逻辑 #
php
public function withValidator($validator)
{
$validator->after(function ($validator) {
// 检查密码强度
if (!$this->isStrongPassword($this->password)) {
$validator->errors()->add(
'password',
'密码必须包含大小写字母、数字和特殊字符'
);
}
// 检查唯一组合
if ($this->hasDuplicateCombination()) {
$validator->errors()->add(
'combination',
'该组合已存在'
);
}
});
}
八、授权失败处理 #
8.1 自定义授权失败响应 #
php
protected function failedAuthorization()
{
throw new HttpResponseException(
response()->json(['message' => '无权执行此操作'], 403)
);
}
8.2 重定向授权失败 #
php
protected function failedAuthorization()
{
throw new HttpResponseException(
redirect()->route('home')->with('error', '无权执行此操作')
);
}
九、验证失败处理 #
9.1 自定义验证失败响应 #
php
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
throw new HttpResponseException(
response()->json([
'message' => '验证失败',
'errors' => $validator->errors(),
], 422)
);
}
十、完整示例 #
10.1 创建用户请求 #
php
// app/Http/Requests/StoreUserRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
class StoreUserRequest extends FormRequest
{
public function authorize()
{
return $this->user()->can('create', User::class);
}
public function rules()
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|min:8|confirmed',
'phone' => 'nullable|regex:/^1[3-9]\d{9}$/',
'avatar' => 'nullable|image|max:1024',
];
}
public function messages()
{
return [
'name.required' => '姓名不能为空',
'email.required' => '邮箱不能为空',
'email.email' => '邮箱格式不正确',
'email.unique' => '该邮箱已被注册',
'password.required' => '密码不能为空',
'password.min' => '密码至少8个字符',
'password.confirmed' => '两次密码不一致',
'phone.regex' => '手机号格式不正确',
'avatar.image' => '头像必须是图片',
'avatar.max' => '头像不能超过1MB',
];
}
public function attributes()
{
return [
'name' => '姓名',
'email' => '邮箱',
'password' => '密码',
'phone' => '手机号',
'avatar' => '头像',
];
}
protected function prepareForValidation()
{
if ($this->phone) {
$this->merge([
'phone' => preg_replace('/[^0-9]/', '', $this->phone),
]);
}
}
protected function passedValidation()
{
$this->merge([
'password' => bcrypt($this->password),
]);
}
}
10.2 更新用户请求 #
php
// app/Http/Requests/UpdateUserRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateUserRequest extends FormRequest
{
public function authorize()
{
return $this->user()->can('update', $this->user);
}
public function rules()
{
$userId = $this->route('user')->id;
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $userId,
'phone' => 'nullable|regex:/^1[3-9]\d{9}$/',
'password' => 'nullable|min:8|confirmed',
];
}
}
10.3 控制器使用 #
php
class UserController extends Controller
{
public function store(StoreUserRequest $request)
{
$user = User::create($request->validated());
if ($request->hasFile('avatar')) {
$user->avatar = $request->file('avatar')->store('avatars');
$user->save();
}
return redirect()->route('users.show', $user)
->with('success', '用户创建成功');
}
public function update(UpdateUserRequest $request, User $user)
{
$data = $request->validated();
if (empty($data['password'])) {
unset($data['password']);
}
$user->update($data);
return redirect()->route('users.show', $user)
->with('success', '用户更新成功');
}
}
十一、最佳实践 #
11.1 请求类命名 #
text
StoreUserRequest - 创建用户
UpdateUserRequest - 更新用户
DeleteUserRequest - 删除用户
ImportUserRequest - 导入用户
11.2 共享基类 #
php
// app/Http/Requests/BaseRequest.php
class BaseRequest extends FormRequest
{
protected function failedAuthorization()
{
abort(403, '无权执行此操作');
}
}
// 使用
class StoreUserRequest extends BaseRequest
{
// ...
}
11.3 复用规则 #
php
class UserRequest extends FormRequest
{
protected function commonRules()
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email',
];
}
}
class StoreUserRequest extends UserRequest
{
public function rules()
{
return array_merge($this->commonRules(), [
'password' => 'required|min:8',
]);
}
}
十二、总结 #
12.1 核心方法 #
| 方法 | 说明 |
|---|---|
| authorize() | 授权检查 |
| rules() | 验证规则 |
| messages() | 错误消息 |
| attributes() | 字段名称 |
| prepareForValidation() | 验证前处理 |
| passedValidation() | 验证后处理 |
| withValidator() | 验证钩子 |
12.2 下一步 #
掌握了表单请求后,让我们继续学习 认证系统,了解Laravel用户认证!
最后更新:2026-03-28