Open erikwittek opened 2 years ago
Thanks for the PR, I didn't even realize that this wasn't currently possible. That being said, this implementation has a couple of issues:
make
) gets completely ignored as soon as you specify the rules as an associative array. This is completely opaque to the user, however, and could lead to hard to track down bugs. Which leads to the next point.Field::make('checkbox')
->rules([
'checkbox' => 'required_if:some_other_field',
'checkbox.*' => 'in:optionA,optionB',
]);
Now the field name has to be mentioned three times.
Here's what I would propose instead.
Field::make(...)
.rules
method of the Field
class stays as it is, i.e. it explicitly configures the rule for the field itself, not for any nested fields.nestedRules
(I'm open for better name suggestions) that only configures the nested rules for this field. This means that any rule you specify in there is implicitly scoped to {fieldname}.*
.Field::make('checkboxes')
// resolves to `['checkboxes' => ['required_if:some_other_field']]`
->rules(['required_if:some_other_field'])
// resolves to `['checkboxes.*' => ['in:optionA,optionB']]`
->nestedRules(['in:optionA,optionB'])
The nestedRules
method could work similar to how your current PR works. If the provided array is not an associated array, we could implicitly treat it as the *
rule. But you could also provide an associative array if you need to nest your rules even further like checkboxes.*.id
.
Field::make('checkboxes')
->nestedRules(['in:optionA,optionB']);
// => ['checkboxes.*' => ['in:optionA,optionB']]
Field::make('options')
->nestedRules([
'id' => 'required',
'name' => ['string', 'max:255']
]);
// => [
// 'options.*.id' => 'required',
// 'options.*.name' => ['string', 'max:255']
// ]
Notice how the names checkboxes
and options
are only mentioned once.
Thank you very much for the Feedback. We've discussed the solution you proposed already but decided against a separate method, because we preferred to have one single place to set all the validation rules.
Nevertheless, your points are valid, so what do you think about a second optional parameter on the ->rules()
method:
function rules($rules, $nested_rules = [])
This would keep everything in one place but at the same time prevent the bugs you mentioned.
Also, I wouldn't set the *
selector implicitly, because I'd prefer the visibility of what I have configured.
Additionally there are situations where you need to define rules for the properties of an object, rather than an array of objects:
Field::make('photos')
->rules([
'photos.profile' => 'required|image',
]);
(Example from: https://laravel.com/docs/8.x/validation#validating-nested-array-input)
This PR lets you define validation rules for nested array input: