Laravel中如何验证数组字段组合符合数据库联合唯一约束?
Laravel 数组参数多字段联合唯一校验实现方法
方法1:动态构建验证规则
一次性生成所有索引对应的验证规则,避免循环调用验证方法:
// 初始化基础规则 $rules = [ 'day.*.day' => ['required'], 'time.*.start_time' => ['required', 'different:time.*.end_time'], 'time.*.end_time' => ['required', 'different:time.*.start_time'], ]; // 遍历所有提交的时间条目索引,追加联合唯一规则 $timeList = request()->input('time', []); foreach (range(0, count($timeList) - 1) as $index) { $rules["day.$index.day"][] = Rule::unique('days') ->where('day', request("day.$index.day")) ->where('start_time', request("time.$index.start_time")) ->where('end_time', request("time.$index.end_time")); // 如果是更新场景,需要忽略当前已存在的记录,添加以下代码 // ->ignore(request("id.$index.id")); } // 执行统一校验 $validated = request()->validate($rules);
方法2:使用闭包规则(更灵活,支持自定义错误提示)
直接在通配符规则内通过闭包处理每个索引的唯一性校验:
use Illuminate\Support\Facades\DB; $validated = request()->validate([ 'day.*.day' => [ 'required', function ($attribute, $value, $fail) { // 提取当前条目的索引 $index = explode('.', $attribute)[1]; $startTime = request("time.$index.start_time"); $endTime = request("time.$index.end_time"); // 查询数据库是否存在重复组合 $exists = DB::table('days') ->where('day', $value) ->where('start_time', $startTime) ->where('end_time', $endTime) // 更新场景下添加忽略当前记录的条件 // ->where('id', '!=', request("id.$index.id")) ->exists(); if ($exists) { $fail('第'.($index + 1).'组时间配置已存在,请勿重复提交'); } } ], 'time.*.start_time' => ['required', 'different:time.*.end_time'], 'time.*.end_time' => ['required', 'different:time.*.start_time'], ]);
注意事项
- 原规则中的
different:time.*.end需修正为different:time.*.end_time,保证和提交的字段名匹配。 - 如果需要校验提交的参数内部是否存在重复组合(未入库就重复),可以额外在闭包内收集所有组合的哈希值,判断是否有重复。
- 不要在循环内调用
request()->validate(),每次验证失败都会直接抛出异常,无法完成全量校验。
内容的提问来源于stack exchange,提问作者I-dont-know-
相关产品推荐
相关产品推荐

