Я хочу получить доступ к информации во вложенном массиве проверки, чтобы выполнить пользовательскую проверку, вот мой код:
return [
...,
'amount' => ['nullable', 'numeric'],
'currency_id' => ['nullable', 'integer', Rule::in($allowedCurrencyIds)],
'details' => ['nullable'],
'details.*.product_id' => ['required', 'integer', 'exists:products,id'],
'details.*.product_collection_id' => [
'nullable',
'integer',
'exists:product_collections,id',
new ProductAndCollectionValidator($this->details.*.->product_id, $this->details->product_collection_id)
],
...
]
Как вы можете видеть, я хочу получить доступ к идентификатору продукта и идентификатору коллекции продуктов с подробной информацией.* для отправки в пользовательский валидатор ProductAndCollectionValidator. И мне нужно учитывать, что иногда product_collection_id может быть нулевым. И это первый шаг.
Второй шаг: я хочу убедиться, что в массиве сведений нет дубликатов Product_id и Product_collection_id.
Как мне это сделать?
вы можете использовать собственные правила проверки и замыкания проверки Laravel. https://laravel.com/docs/11.x/validation#using-closures. Попробуйте это на своем валидаторе:
return [
// Other validation rules...
'details.*.product_id' => ['required', 'integer', 'exists:products,id'],
'details.*.product_collection_id' => [
'nullable',
'integer',
'exists:product_collections,id',
function ($attribute, $value, $fail) {
// Accessing nested values within details array
$productId = $this->input('details')[$this->getIndexFromAttribute($attribute)]['product_id'];
// Custom validation logic using ProductAndCollectionValidator
$validator = new ProductAndCollectionValidator($productId, $value);
if (!$validator->passes()) {
$fail($validator->message());
}
}
],
'details' => ['nullable', function ($attribute, $value, $fail) {
// Custom validation rule to check for duplicates
$uniqueDetails = collect($value)->unique(function ($detail) {
return $detail['product_id'] . '-' . $detail['product_collection_id'];
});
if ($uniqueDetails->count() !== count($value)) {
$fail('Duplicate product_id and product_collection_id combinations found.');
}
}],
];
function getIndexFromAttribute($attribute)
{
return explode('.', str_replace(['[*]', '*'], ['.', ''], $attribute))[1];
}
Дайте мне знать. Ваше здоровье.
Вот 2 решения. Я не проверял. Пожалуйста, дайте мне знать, если есть ошибка.
Запрос:
return [
...,
'amount' => ['nullable', 'numeric'],
'currency_id' => ['nullable', 'integer', Rule::in($allowedCurrencyIds)],
'details' => ['nullable', 'array', new ArrayUniqueItems(['product_id', 'product_collection_id'])],
'details.*.product_id' => ['required', 'integer', 'exists:products,id'],
'details.*.product_collection_id' => ['nullable', 'integer', 'exists:product_collections,id'],
...
];
Правило:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\ValidationRule;
class ArrayUniqueItems implements ValidationRule
{
public function __construct(private arrray $keys) {}
public function __invoke($attribute, $value, $fail): void
{
foreach ($keys as $key) {
collect(collect($value)->duplicates($key))
->each(fn ($item, $index) => $fail(
"$attribute.$index.product_id",
"Duplicate $key"),
);
}
}
}
Запрос:
return [
...,
'amount' => ['nullable', 'numeric'],
'currency_id' => ['nullable', 'integer', Rule::in($allowedCurrencyIds)],
'details' => ['nullable', 'array'],
'details.*.product_id' => ['required', 'integer', 'exists:products,id', new UniqueInArray('product_id')],
'details.*.product_collection_id' => ['nullable', 'integer', 'exists:product_collections,id'],
...
];
Правило:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\ValidationRule;
class UniqueInArray implements ValidationRule, DataAwareRule
{
/**
* All of the data under validation.
*
* @var array<string, mixed>
*/
protected $data = [];
public function __invoke($attribute, $value, $fail): void
{
// This part is not safe but gives an idea to find the index
$root = explode('.', $attribute)[0];
$index = (int) explode('.', $attribute)[1];
$key = explode('.', $attribute)[2];
$duplicates = collect($this->data[$root] ?? [])->duplicates($key);
if (array_key_exists($index, $duplicates)) {
$fail($attribute, "Duplicate $key");
}
}
/**
* Set the data under validation.
*
* @param array<string, mixed> $data
*/
public function setData(array $data): static
{
$this->data = $data;
return $this;
}
}