如何在Laravel Backpack中正确校验Checklist字段?
问题背景
我通过Laravel Backpack创建了一个Checklist字段,定义如下:
$this->crud->addField( [ // Checklist 'label' => '<b>IDIOMAS</b>', 'type' => 'checklist', 'name' => 'idiomas', 'entity' => 'idiomas', 'attribute' => 'titulo', 'model' => "App\Models\Idioma", 'pivot' => false, 'number_of_columns' => 3, 'wrapper' => [ 'class' => 'form-group col-md-6', ], 'tab' => 'HABILIDADES', ] );
原本想用以下规则强制用户至少选择一个选项:
'idiomas' => 'required|array|min:1', //'idiomas.*' => 'required|integer|exists:idiomas,id',
但校验始终无效。查看生成的HTML,发现表单末尾有一个隐藏字段:
<input type="hidden" value="[]" name="idiomas">
这导致校验时接收到的是字符串"[]"而非数组,无法触发数组相关的校验规则。目前临时使用required|min:3的规则并自定义提示信息,但想知道是否有更优方案,以及Backpack返回的待校验值形式是否正确。
优化解决方案
1. 在请求类中转换字段格式
在对应的表单请求类中,通过prepareForValidation方法将字符串格式的idiomas转换为数组,这样就能正常使用数组校验规则:
protected function prepareForValidation() { $this->merge([ 'idiomas' => json_decode($this->input('idiomas'), true) ?: [], ]); }
转换后,原有的校验规则required|array|min:1即可生效,还能启用idiomas.*的子项校验规则。
2. 禁用隐藏默认字段
部分Laravel Backpack版本的Checklist字段支持通过hidden_input参数禁用那个生成默认空数组字符串的隐藏字段。在字段定义中添加该参数:
$this->crud->addField( [ // ... 其他字段配置 'hidden_input' => false, ] );
禁用后,当用户未选择任何选项时,idiomas字段不会出现在请求中,此时required|array|min:1规则会正确触发必填校验,符合需求。
3. 自定义校验规则(备选方案)
如果上述方法无法适配你的Backpack版本,可以编写自定义校验规则,判断字段值是否为有效选中的数组:
Validator::extend('checklist_min', function ($attribute, $value, $parameters, $validator) { $array = json_decode($value, true) ?: []; return count($array) >= $parameters[0]; });
使用时规则写成:
'idiomas' => 'required|checklist_min:1',
并自定义提示信息:
'idiomas.checklist_min' => 'Debe seleccionar al menos un elemento',
关于Backpack返回值的疑问
Backpack生成这个隐藏字段的初衷是为了避免表单不提交数组字段(比如用户未选任何选项时,HTTP请求中不会包含该字段),但将默认值设为字符串"[]"的设计并不合理,正确的处理应该是提交空数组而非字符串。不过这个问题可以通过上述解决方案轻松规避。
内容的提问来源于stack exchange,提问作者Camus

