Laravel Object Validation Closure
I’m using Laravel Inertia and the resulting form submission returns JSON objects - which I wanted to validate.
In my case I have a quiz - which has questions which in turn have answers and those answers have user-submitted responses.
If the CMS editor tries to delete answers which have responses this will result in an SQL referential integrity error - so I want a validation rule for each answer which says
If the answer object has property “deleted” and the database has responses for this answer - fail.
Request file
QuizUpdateRequest.php looks like
<?php
namespace App\Http\Requests;
use Closure;
use DB;
use Illuminate\Foundation\Http\FormRequest;
class QuizUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'questions.*.answers.*' => function (string $attribute, mixed $value, Closure $fail) {
if ($value['deleted'] ?? false) {
$responses = DB::table('quiz_responses')->where('quiz_answer_id', $value['id'])->exists();
if ($responses) {
$fail('Cannot delete : The answer has responses.');
}
}
},
];
}
}
Post Object
I’m using inertiaJS and posting an object like below (edited for clarity)
Note one answer has deleted : true
which marks it for deletion.
{
"questions": [
{
"id": 90160,
"question": "fghfgfcg",
"answers": [
{
"id": 90634,
"answer": "fghfghfgh",
},
{
"id": 90636,
"answer": "asdfasdf",
"deleted": true
}
]
}
]
}
Solution
All the examples I saw in the Laravel docs are for validation rules on individual fields
But when I used questions.*.answers.*
the $value object captures each answer with $value['deleted']
and $value['id']
both available in the closure.
This makes it simple to take one property - the deleted flag to see that the validation is needed. Then use another property - the id - to look for responses and fail if they exist.