You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();

代码解释

  1. 路径解析:通过拆解当前验证字段的attribute字符串(比如categories.0.fields.1.rules.0.from),我们可以动态生成对应的type字段路径(categories.0.fields.1.type),然后用data_get()获取该字段的值。
  2. 动态规则:Rule::when()会根据回调函数的返回值,决定是否添加对应的验证规则(numeric或date)。
  3. 必填规则:因为无论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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:47:01