To get the proper validation array back you should build up the rules before you run the validation. It doesn't work when you build up this array in one of the validation rules. There are a ton of options to do this, so I think you can figure this out yourself ;)
Validating complex array with dynamic content
Hey everyone!
I'm currently learning Laravel, working on a hobby project where leaders of a guild can vote on their guild members. Running PHP 8.1 & the latest version of Laravel Jetstream with Inertia.
I've hit a wall however trying to validate a complex array. The hack I've come up with, feels dirty and the validation rules are not being returned properly. I'd love to know if there is a better approach.
UI for creating new conditions, with these conditions a new vote can be created and a player will show up in the voting list if the conditions are matched
As you can see in the image above, there can be multiple conditions which each have different options. For example:
The condition "if hours online" has the following options: "Is greater than", "Is less than", "Is equal to". However the condition "if is in current rank" has other options like "for more than". So for each condition different validation rules have to be applied, which makes it a bit tricky.
//Here is an example how the server receives the request data
[
{
"rankId": 17,
"promote": [
{
"condition": 2,
"option": "is greater than",
"firstValue": "30",
"timeValue": "30"
},
{
"condition": 5,
"option": "for more than",
"firstValue": "30",
"timeValue": null
}
],
"demote": []
},
//...
{
"rankId": 18,
"promote": [],
"demote": []
}
]
So I created the following FormRequest
//VoteSettingsRequest.php
public function rules(): array
{
return [
'*.promote.*' => [
'required',
new VoteSettingsConditionRule,
],
'*.demote.*' => [
'required',
new VoteSettingsConditionRule,
],
];
}
And created a custom Validation Rule
//VoteSettingsConditionRule.php
class VoteSettingsConditionRule implements Rule
{
/** @var \Illuminate\Validation\ValidationException */
private $errorMessage;
public function passes($attribute, $value): bool
{
try {
$validatedCondition = match($value['condition']) {
1, 2 => Validator::make($value, [
'condition' => ['required', 'numeric'],
'option' => ['required', 'string', 'in:is greater than,is lower than,equals to'],
'firstValue' => ['required', 'numeric'],
'timeValue' => ['required', 'numeric']
]),
3 => Validator::make($value, [
'condition' => ['required', 'numeric'],
'option' => ['required', 'string', 'in:equals to'],
'firstValue' => ['required', 'in:Premium account,Free account'],
]),
4 => Validator::make($value, [
'condition' => ['required', 'numeric'],
'option' => ['required', 'string', 'in:is greater than,is lower than,equals to'],
'firstValue' => ['required', 'numeric']
]),
5 => Validator::make($value, [
'condition' => ['required', 'numeric'],
'option' => ['required', 'string', 'in:for more than'],
'firstValue' => ['required', 'numeric'],
]),
default => false
};
if(! $validatedCondition->validate()) {
$this->errorMessage = $validatedCondition->messages();
return false;
}
} catch (\Exception $exception) {
$this->errorMessage = $exception;
return false;
}
return true;
}
public function message(): array
{
return collect($this->errorMessage->validator->getMessageBag()->getMessages())
->flatten()
->toArray();
}
}
With this approach however the error bag that gets returned to the frontend does not contain all the fields required to display the right validation.
Sure I might get it to work eventually but it doesn't feel elegant or like a Laravel way... Hope someone can get me heading in the right direction!

//Returned Error Bag after a failed validation
{
"errorBags": {
"default": {
"0.promote.0": [
"The first value field is required.",
"The time value field is required."
]
}
},
"errors": {
"0.promote.0": "The first value field is required."
},
}
Please or to participate in this conversation.