本文目录导读:

在 Laravel 中编写动态验证规则有多种方式,以下是几种常用的实现方法:
基于请求数据动态生成规则
public function store(Request $request)
{
$rules = [];
// 根据条件添加规则
if ($request->has('email')) {
$rules['email'] = 'required|email|unique:users';
}
if ($request->input('type') === 'individual') {
$rules['first_name'] = 'required|string|max:50';
$rules['last_name'] = 'required|string|max:50';
} else {
$rules['company_name'] = 'required|string|max:100';
$rules['tax_id'] = 'required|string|size:18';
}
// 根据用户角色动态设置规则
if (auth()->user()->role === 'admin') {
$rules['status'] = 'required|in:active,inactive,pending';
} else {
$rules['status'] = 'required|in:pending';
}
$validated = $request->validate($rules);
}
使用自定义 FormRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class DynamicUserRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
$rules = [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $this->route('user'),
];
// 动态添加规则
if ($this->input('type') === 'employee') {
$rules['department'] = 'required|string|max:100';
$rules['employee_id'] = 'required|string|unique:employees';
}
if ($this->isMethod('PATCH')) {
$rules['email'] = 'sometimes|email|unique:users,email,' . $this->route('user');
}
// 根据用户权限
if ($this->user()->can('assign-roles')) {
$rules['role'] = 'required|exists:roles,id';
}
return $rules;
}
public function messages()
{
return [
'name.required' => '姓名是必填项',
'email.required' => '邮箱是必填项',
];
}
}
使用闭包规则
use Illuminate\Validation\Rule;
$rules = [
'email' => [
'required',
'email',
function ($attribute, $value, $fail) {
// 动态检查逻辑
if (strpos($value, '@example.com') !== false) {
$fail('不能使用 example.com 邮箱');
}
},
],
'status' => [
'required',
Rule::in(['active', 'inactive', 'pending']),
],
'age' => [
'required',
'numeric',
function ($attribute, $value, $fail) use ($request) {
$minAge = $request->input('type') === 'adult' ? 18 : 0;
if ($value < $minAge) {
$fail("年龄不能小于 {$minAge} 岁");
}
},
],
];
使用 Validator 门面
use Illuminate\Support\Facades\Validator;
public function dynamicValidation(Request $request)
{
$rules = [
'name' => 'required|string|max:255',
];
$messages = [
'name.required' => '名称不能为空',
];
// 根据条件添加规则
if ($request->input('has_email', false)) {
$rules['email'] = 'required|email|unique:users';
}
if ($request->file('avatar')) {
$rules['avatar'] = 'image|mimes:jpeg,png|max:2048';
}
$validator = Validator::make($request->all(), $rules, $messages);
// 自定义验证后处理
$validator->after(function ($validator) use ($request) {
if ($request->input('password') !== $request->input('password_confirmation')) {
$validator->errors()->add('password', '两次密码不一致');
}
// 检查数据库是否存在
if (User::where('email', $request->input('email'))->exists()) {
$validator->errors()->add('email', '邮箱已存在');
}
});
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}
// 验证通过
$validated = $validator->validated();
}
使用条件规则 (Laravel 8+)
use Illuminate\Validation\Rule;
$rules = [
'type' => 'required|in:individual,company',
'email' => 'required|email',
// 当 type 为 individual 时必填
'first_name' => Rule::when($request->input('type') === 'individual', [
'required', 'string', 'max:50'
]),
// 当 type 为 company 时必填
'company_name' => Rule::when($request->input('type') === 'company', [
'required', 'string', 'max:100'
]),
// 多条件组合
'discount_code' => Rule::when(
$request->input('amount') > 100 && $request->input('has_coupon'),
['required', 'string', 'exists:coupons,code']
),
];
高级动态规则示例
public function createOrder(Request $request)
{
$rules = [
'items' => 'required|array',
'items.*.product_id' => 'required|exists:products,id',
'items.*.quantity' => 'required|integer|min:1',
];
// 根据商品类型动态添加规则
foreach ($request->input('items', []) as $index => $item) {
$product = Product::find($item['product_id']);
if ($product) {
if ($product->type === 'digital') {
$rules["items.{$index}.download_link"] = 'required|url';
} elseif ($product->type === 'physical') {
$rules["items.{$index}.shipping_address"] = 'required|string';
}
// 库存验证
if ($item['quantity'] > $product->stock) {
$rules["items.{$index}.quantity"] = [
'required',
'integer',
'min:1',
"max:{$product->stock}"
];
}
}
}
$validated = $request->validate($rules);
}
最佳实践建议
- 使用 FormRequest 类分离验证逻辑
- 善用 Rule::when() 条件规则
- 避免在控制器中写复杂验证,创建专门的验证类
- 使用 Validator::make() 进行复杂场景验证
- 善用闭包规则 处理特殊逻辑
- 保持规则可读性,复杂逻辑拆分成多个方法
选择哪种方式取决于你的具体业务需求和代码组织偏好。