Laravel二维数组字段验证需显式启用通配符支持,用items.*.name等格式而非items.name;规则如required、numeric直接适用,但unique需手动去重校验,max限制总数用items=>max:10,空值和数据形态须前置兜底处理。

验证二维数组中某个字段是否必填(如 items.*.name)
直接用 required 不行——Laravel 默认会把 items 当成一个整体,不会自动展开嵌套结构。必须显式启用数组通配符验证支持。
实操建议:
- 在表单请求类(
FormRequest)的rules()方法中,用items.*.name作为键名,不是items.name或items.0.name - 确保传入的数据是标准二维数组格式,例如:
{"items": [{"name": "foo"}, {"name": ""}]},而不是字符串化的 JSON 字段 - 如果前端用 JS 动态增删行,注意空行可能提交
{"name": null}或{"name": ""},此时需配合required_without_all:items.*.id或自定义规则做空值过滤
对二维数组每个子项的字段做独立规则校验(如 items.*.price 必须为数字且 > 0)
Laravel 原生支持通配符规则,但容易忽略两点:一是规则不继承父级缺失时的跳过逻辑,二是 numeric 对字符串 "12.5" 有效,但 "12.50" 在某些 PHP 版本下会被 filter_var(..., FILTER_VALIDATE_FLOAT) 拒绝。
实操建议:
- 写成
'items.*.price' => ['required', 'numeric', 'gt:0']即可,无需循环或闭包 - 避免用
min:0.01校验小数,它按字符串长度比,应改用gt:0或between:0.01,999999.99 - 若需保留两位小数精度,不要在验证层做格式化,改用存库前 cast 或 mutator 处理
自定义规则判断二维数组中某字段值不能重复(如所有 items.*.sku 唯一)
原生 unique 规则不支持通配符去重,distinct 只作用于一维数组。必须手动提取、去重、比对。
实操建议:
- 在
FormRequest中覆盖withValidator(),用$validator->after()做后置校验 - 提取值用
data_get($this->all(), 'items.*.sku')(比array_column($items, 'sku')更安全,能处理缺失键) - 去重后对比数量:
if (count($skus) !== count(array_unique($skus))) { $validator->errors()->add('items.*.sku', 'SKU 不能重复'); } - 注意:
array_unique对null和空字符串视为相同,如有业务允许空 SKU,需先array_filter($skus, 'strlen')
验证二维数组长度并限制最大项数(如最多 10 个 items)
size、max 等规则默认只认顶层字段,items 是数组,所以 'items' => 'max:10' 是有效的;但若你写了 'items.*' => 'max:10' 就完全无效——Laravel 不解析这种写法。
实操建议:
- 限制总数:直接写
'items' => 'array|max:10',array是必须的,否则max会尝试转为整型比较而报错 - 限制每项字段长度(如每个
name最多 50 字):用'items.*.name' => 'string|max:50' - 若需动态限制(如 VIP 用户允许 20 条),不要硬编码,改用闭包规则:
'items' => [function ($attribute, $value, $fail) { $max = auth()->user()?->is_vip ? 20 : 10; if (count($value) > $max) { $fail("最多只能添加 {$max} 个商品"); } }]
二维数组验证真正麻烦的不是写法,而是数据形态不一致:前端可能漏传 items 键、传空数组、或混入非数组值。务必在验证前用 data_fill($this->all(), 'items', []) 做兜底,再进规则链。


















