I got a Laravel FormRequest class that should validate two JSON query strings (nested objects and arrays) on a GET route on my JSON Rest API. I pick up the json query strings, decode them to php objects and store them during validation prepare time on the request for validation.
For some reason, this seems not to work properly. The 'sorters' json validation is working, as is the 'sorters_decoded' validation for 'required' and 'array'. The array element validation and everything after seems not to work since i reach the controller function even if invalid data is sent. The query input bag collection on the request is modified (invalid data is set to null) but no validation 422 response is generated. Do you maybe see something wrong with this code?
class RecipeFindRequest extends FormRequest
{
protected function prepareForValidation(): void
{
try {
$sorters = null;
if ($this->query->has('sorters')) {
$sorters = json_decode($this->query->get('sorters'));
$this->merge([
'sorters_decoded' => $sorters,
]);
}
$filters = null;
if ($this->query->has('filters')) {
$filters = json_decode($this->query->get('filters'));
$this->merge([
'filters_decoded' => $filters,
]);
}
$this->merge([
'language' => $this->headers->get('language'),
]);
} catch(\Throwable $e) {
//die silently, fail response will get raised on validation time
}
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules(): array
{
return [
'sorters' => ['json'],
'sorters_decoded' => ['required', 'array'],
'sorters_decoded.*.name' => ['required', 'string', Rule::in(['likes', 'ratings', 'calories', 'carbs', 'protein', 'fat', 'created'])],
'sorters_decoded.*.direction' => ['required', 'string', Rule::in(['asc', 'desc'])],
'sorters_decoded.*.order' => ['required', 'integer'],
'filters' => ['json'],
'filters_decoded.duration_high' => ['integer', 'min:0'],
'filters_decoded.duration_low' => ['integer', 'min:0'],
'filters_decoded.title' => ['string'],
'filters_decoded.difficulty' => ['array'],
'filters_decoded.difficulty.*' => ['string', 'exists:difficulties,id'],
'filters_decoded.ingredients' => ['array'],
'filters_decoded.ingredients.*.id' => ['string', 'exists:ingredients,id'],
'filters_decoded.ingredients.*.relation' => ['string', Rule::in(['include', 'exclude'])],
'filters_decoded.liked_by_me' => ['boolean'],
'filters_decoded.cookbooks' => ['array'],
'filters_decoded.cookbooks.*' => ['string', 'exists:cookbooks,id'],
'filters_decoded.nutritions' => ['array'],
'filters_decoded.nutritions.*.category_id' => ['string', 'exists:nutrition_categories,id'],
'filters_decoded.nutritions.*.nutrition_high' => ['numeric', 'min:0'],
'filters_decoded.nutritions.*.nutrition_low' => ['numeric', 'min:0'],
'language' => ['string', 'size:2', 'exists:i18n_languages,short'],
'page' => ['integer', 'min:1'],
'per_page' => ['integer', 'min:1'],
];
}
}
Both params are sent as json query strings and the decoding step works, so its not something to do with url de/encoding.
I tried to change the sorters.*.name array element validation from string to integer, and when i sent in some data like [{'name':'a'}] the 'integer' validation changed the data in $response->query->sorters_decoded to [{'name':null}]. But no 422 validation fail response came up.

dump($this->sorters_decoded)to see if the structure matches up with what you expect? (Do not include pictures of text in your question, it is not accessible or reusable.)prepareForValidation()you would need to a) not consume the exception and b) telljson_decode()to throw exceptions – it does not do this by default.array(1) { [0]=> object(stdClass)#1450 (3) { ["name"]=> string(5) "likes" ["direction"]=> string(3) "asc" ["order"]=> int(1) } }