I have an endpoint that accepts and array of IDs in this format:
{
"data": [
{
"id": 1
},
{
"id": 2
},
{
"id": 4
}
]
}
...and in my validation requests file I have:
<?php
namespace AppNew\Http\Requests;
use Illuminate\Validation\Rule;
use Illuminate\Database\Query\Builder;
use Illuminate\Foundation\Http\FormRequest;
class ArchivePostsCollectionRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules(): array
{
return [
'data' => [
'array',
],
'data.*' => [
'required',
'array',
],
'data.*.id' => [
'required',
'integer',
'distinct',
Rule::exists('posts', 'posts.id')->where(function (Builder $query) {
return $query->where('posts.is_default', false);
}),
],
];
}
public function messages(): array
{
return [
'data.array' => 'Expected an array!',
'data.*' => 'Expected an array of objects!',
'data.*.id.required' => 'Expected an ID!',
'data.*.id.integer' => 'Expected an integer for ID!',
'data.*.id.integer' => 'Expected distinct IDs!',
'data.*.id.exists' => 'Selected post is set to default and cannot be archived!',
];
}
}
I want to add another rule to check that each post ID does not have comments; the comments table has a post_id column to check against. However I am stumped as to how to approach this from a Rule perspective!
Any pointers greatly appreciated.
Thanks, K...
You can do this in a couple different ways:
'data.*.id' => [
'required',
'integer',
'distinct',
Rule::exists('posts', 'posts.id')->where(function (Builder $query) {
return $query->where('posts.is_default', false);
}),
function (string $attribute, mixed $value, Closure $fail) {
if (DB::table('comments')->where('post_id', $value)->count() !== 0) {
$fail('Post has comments!');
}
},
],
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class PostWithoutCommentsRule implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (DB::table('comments')->where('post_id', $value)->count() !== 0) {
$fail('Post has comments!');
}
}
}
'data.*.id' => [
'required',
'integer',
'distinct',
Rule::exists('posts', 'posts.id')->where(function (Builder $query) {
return $query->where('posts.is_default', false);
}),
new PostWithoutCommentsRule,
],
It really depends on how often you'll use it. If it's simple, I use closures. If it's complex, I use validator after. If it's something that's used more than once, no matter the complexity, I use custom Rules.