Laravel validate_if规则实现嵌套数组动态验证需求
解决Laravel中嵌套数组的条件验证问题
嘿,这个场景我之前在项目里碰到过,Laravel的条件验证机制完全能轻松搞定这种混合类型的嵌套数组验证需求,不用头疼逐个判断fields里的元素类型!
核心思路
我们需要针对每个categories.*.fields.*的type值,动态给对应的rules.*.from和to设置验证规则:
- 当
type为numbers时,from和to必须是必填数字 - 当
type为dates时,from和to必须是必填日期格式
完整验证规则实现
我们可以用Laravel的Rule::when()方法来实现动态条件验证,结合数组路径解析来关联对应的type字段:
use Illuminate\Validation\Rule; $validationRules = [ // 验证顶层categories数组结构 'categories' => 'required|array', 'categories.*.name' => 'required|string', // 验证每个category下的fields数组 'categories.*.fields' => 'required|array', 'categories.*.fields.*.type' => 'required|in:numbers,dates', 'categories.*.fields.*.name' => 'required|string', // 验证每个field下的rules数组 'categories.*.fields.*.rules' => 'required|array', 'categories.*.fields.*.rules.*.rate' => 'required|numeric', // 可选字段的宽松验证 'categories.*.fields.*.rules.*.label' => 'nullable|string', 'categories.*.fields.*.rules.*.value' => 'nullable|numeric', // 核心:针对from字段的条件验证 'categories.*.fields.*.rules.*.from' => [ 'required', Rule::when(function ($input, $attribute) { // 解析当前from字段对应的fields.type路径 $pathParts = explode('.', $attribute); // 把路径末尾的rules.*.from替换为type array_splice($pathParts, -3, 3, ['type']); $typeFieldPath = implode('.', $pathParts); // 如果对应的type是numbers,要求为数字 return data_get($input, $typeFieldPath) === 'numbers'; }, ['numeric']), Rule::when(function ($input, $attribute) { $pathParts = explode('.', $attribute); array_splice($pathParts, -3, 3, ['type']); $typeFieldPath = implode('.', $pathParts); // 如果对应的type是dates,要求为日期格式 return data_get($input, $typeFieldPath) === 'dates'; }, ['date']), ], // to字段的验证逻辑和from完全一致 'categories.*.fields.*.rules.*.to' => [ 'required', Rule::when(function ($input, $attribute) { $pathParts = explode('.', $attribute); array_splice($pathParts, -3, 3, ['type']); $typeFieldPath = implode('.', $pathParts); return data_get($input, $typeFieldPath) === 'numbers'; }, ['numeric']), Rule::when(function ($input, $attribute) { $pathParts = explode('.', $attribute); array_splice($pathParts, -3, 3, ['type']); $typeFieldPath = implode('.', $pathParts); return data_get($input, $typeFieldPath) === 'dates'; }, ['date']), ], ]; // 执行验证 $validatedData = \Illuminate\Support\Facades\Validator::make($request->all(), $validationRules)->validate();
代码解释
- 路径解析:通过拆解当前验证字段的
attribute字符串(比如categories.0.fields.1.rules.0.from),我们可以动态生成对应的type字段路径(categories.0.fields.1.type),然后用data_get()获取该字段的值。 - 动态规则:
Rule::when()会根据回调函数的返回值,决定是否添加对应的验证规则(numeric或date)。 - 必填规则:因为无论
type是哪种,from和to都是必填的,所以直接添加required规则即可,不用重复写required_if。
测试示例
比如以下输入会顺利通过验证:
$testInput = [ 'categories' => [ [ 'name' => '薪资分类', 'fields' => [ [ 'type' => 'numbers', 'name' => '基本工资', 'rules' => [ ['from' => 3000, 'to' => 10000, 'rate' => 0.2, 'label' => '普通薪资段'] ] ], [ 'type' => 'dates', 'name' => '年终奖周期', 'rules' => [ ['from' => '2024-01-01', 'to' => '2024-12-31', 'rate' => 0.15] ] ] ] ] ] ];
如果把numbers类型的from写成字符串(比如"3000"),或者dates类型的from写成数字,验证器会直接抛出对应的错误提示。
内容的提问来源于stack exchange,提问作者Dmitry Likhovoi
相关产品推荐
相关产品推荐

