Laravel动态验证规则怎么写

wen PHP项目 2

本文目录导读:

Laravel动态验证规则怎么写

  1. 基于请求数据动态生成规则
  2. 使用自定义 FormRequest
  3. 使用闭包规则
  4. 使用 Validator 门面
  5. 使用条件规则 (Laravel 8+)
  6. 高级动态规则示例
  7. 最佳实践建议

在 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);
}

最佳实践建议

  1. 使用 FormRequest 类分离验证逻辑
  2. 善用 Rule::when() 条件规则
  3. 避免在控制器中写复杂验证,创建专门的验证类
  4. 使用 Validator::make() 进行复杂场景验证
  5. 善用闭包规则 处理特殊逻辑
  6. 保持规则可读性,复杂逻辑拆分成多个方法

选择哪种方式取决于你的具体业务需求和代码组织偏好。

抱歉,评论功能暂时关闭!