Laravel – доступ к информации с помощью вложенного запроса проверки

Я хочу получить доступ к информации во вложенном массиве проверки, чтобы выполнить пользовательскую проверку, вот мой код:

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.

Как мне это сделать?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
0
0
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

вы можете использовать собственные правила проверки и замыкания проверки 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 решения. Я не проверял. Пожалуйста, дайте мне знать, если есть ошибка.

  1. Вы можете создать одно собственное правило для массива данных:

Запрос:

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"),
                );
        }
    }
}
  1. Вы можете создать элементы данных собственного правила:

Запрос:

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;
    }
}

Другие вопросы по теме