Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама
Новини 08 серпня 2026

Валідація ключів масиву в Laravel: нове правило array_keys

Ендпоінти, які приймають набір опцій, мають тихий режим відмови. Клієнт надсилає ?filter[stat us]=draft з друкарською помилкою, ваш код читає $filters['status'], нічого не знаходить і повертає нефільтрований список. Ніхто не отримує помилку, відповідь виглядає нормально, а баг спливає пізніше як "фільтр іноді не працює".

Laravel 13.24 додає правило валідації array_keys саме для цього: масив може містити ці ключі і нічого більше, з повідомленням про помилку, яке вказує, що пішло не так.

Правило валідації

Працюють як builder-форма, так і рядкова:

use Illuminate\Validation\Rule;
$request->validate([
    'filter' => Rule::arrayKeys(['status', 'author', 'tag']),
]);
// Еквівалент
$request->validate([
    'filter' => 'array_keys:status,author,tag',
]);

Якщо передано ['status' => 'draft', 'stat us' => 'draft'], валідація завершиться з помилкою:

The filter field must only contain the following keys: status, author, tag.

Ключі є дозволеними, але не обов'язковими. Правило обмежує те, що може з'явитися, але не вимагає обов'язкової присутності. Якщо потрібна друга половина, required_array_keys все ще покриває це, і обидва правила можна комбінувати:

'coordinates' => [
    'required_array_keys:lat,lng',
    Rule::arrayKeys(['lat', 'lng']),
],

Ця пара читається як "точно ці ключі, не більше і не менше".

Чому не array:key_1,key_2?

Rule::array() вже деякий час приймає список ключів і справді відхиляє неочікувані ключі. Різниця полягає в тому, що відбувається при помилці. Правило array відповідає на два запитання: "це масив?" і "він містить тільки ці ключі?", і повідомляє про обидва одним повідомленням:

Правило Повідомлення для ['status' => 'draft', 'colour' => 'red']
array:status,author The filter field must be an array.
array_keys:status,author The filter field must only contain the following keys: status, author.

Перше повідомлення активно вводить в оману, оскільки значення є масивом. Також немає placeholder для проблемних ключів, тому неможливо написати власне повідомлення, яке їх називає.

Обидва правила звітуються окремо в $validator->failed() як Array та ArrayKeys, тому можна застосовувати обидва, коли потрібно розрізняти кожну помилку:

'filter' => ['array', Rule::arrayKeys(['status', 'author', 'tag'])],

Rule::array() та його повідомлення залишаються незмінними, тому нічого з уже написаного коду не поводиться інакше.

Вказування проблемних ключів

Правило постачається з двома placeholder. :values містить прийняті ключі і використовується в стандартному повідомленні. :unexpected містить ключі, які фактично спричинили помилку, і хоча він не використовується в стандартному повідомленні, зазвичай це кориснішша половина у відповіді API:

$request->validate(
    ['filter' => Rule::arrayKeys(['status', 'author', 'tag'])],
    ['filter.array_keys' => 'The :attribute field may not contain :unexpected.'],
);
// The filter field may not contain colour, sort.

Вказуючи клієнту, який ключ він зробив неправильно, ви перетворюєте гру в здогадки на виправлення в один рядок, що варте власного повідомлення в публічному API.

Приклад фільтрованого ендпоінту

Об'єднуючи все разом на маршруті, який приймає фільтри, сортування та include з власним набором дозволених ключів:

namespace App\Http\Requests;

use App\Enums\PostStatus;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class IndexPostRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'filter' => ['sometimes', 'array', Rule::arrayKeys(['status', 'author', 'tag'])],
            'filter.status' => ['sometimes', Rule::enum(PostStatus::class)],
            'filter.author' => ['sometimes', 'integer', 'exists:users,id'],
            'filter.tag' => ['sometimes', 'string', 'max:50'],
            'sort' => ['sometimes', 'string', Rule::in(['title', '-title', 'published_at', '-published_at'])],
        ];
    }

    public function messages(): array
    {
        return [
            'filter.array_keys' => 'Unknown filter: :unexpected. Allowed filters are :values.',
        ];
    }
}

Контролер може тоді читати набір фільтрів без захисних перевірок, оскільки все, що до нього дійшло, є ключем, який ви вказали:

public function index(IndexPostRequest $request)
{
    $filters = $request->validated('filter', []);
    return PostResource::collection(
        Post::query()
            ->when($filters['status'] ?? null, fn ($q, $status) => $q->where('status', $status))
            ->when($filters['author'] ?? null, fn ($q, $author) => $q->where('user_id', $author))
            ->when($filters['tag'] ?? null, fn ($q, $tag) => $q->whereRelation('tags', 'slug', $tag))
            ->paginate()
    );
}

Без цього правила ?filter[autor]=3 повертає всі пости і виглядає як робочий запит. З ним клієнт отримує 422 з вказівкою на autor.

Валідація JSON-колонки

Те саме правило корисне при записі даних, де колонка налаштувань або уподобань схильна накопичувати все, що випадково надіслав frontend:

'preferences' => ['sometimes', 'array', Rule::arrayKeys(['theme', 'timezone', 'digest_frequency'])],
'preferences.theme' => ['sometimes', Rule::in(['light', 'dark', 'system'])],
'preferences.timezone' => ['sometimes', 'timezone'],
'preferences.digest_frequency' => ['sometimes', Rule::in(['daily', 'weekly', 'never'])],

Перейменоване поле frontend тепер явно падає під час розгортання замість того, щоб записувати ключ, який ніхто не читає, у кожен рядок.

Деталі, які варто знати

Кілька особливостей поведінки, які не очевидні з повідомлення:

  • Значення, яке не є масивом, не проходить правило. Передача 'filter' => 'draft' створює повідомлення "must only contain the following keys", яке читається дивно для рядка. Поєднуйте його з array, коли вхідні дані можуть взагалі не бути масивом, щоб помилка типу повідомлялася окремо.

  • Правило потребує принаймні одного ключа. Написання 'array_keys' без ключів викликає InvalidArgumentException під час виконання валідації, а не провалює поле. Немає форми "не дозволяти нічого"; цей випадок покриває prohibited.

  • Ключі можуть походити з будь-якого Arrayable. Працюють колекція або список на основі enum, а backed enum розв'язуються до їхніх значень:

Rule::arrayKeys(FilterKey::cases());
Rule::arrayKeys(collect(config('filters.allowed')));
  • Варіативна форма теж працює. Rule::arrayKeys('status', 'author') еквівалентна передачі масиву, що зручно для inline-використання.

Правило було внесено @nebarg у #60918.

7

Читати в документації

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Читайте також

Filament v5.10.0
Новини 12 жовтня 2026

Filament v5.10.0: сітка в rich editor, скелетони таблиць і десятки виправлень

Вийшов Filament v5.10.0: елементи керування сіткою в rich editor, допоміжний контент для віджетів-графіків, скелетони завантаження таблиць, submitOnCompletion() для OneTimeCodeInput та багато виправлень авторизації, доступності й стану.

18
Laravel AI SDK на практиці
Новини 09 жовтня 2026

Laravel AI SDK на практиці: агент, що стоїть за There There

Фрік Ван дер Гертен розповідає, як у Spatie побудували AI-шар хелпдеска There There на Laravel AI SDK: клас агента, інструменти з типізованою JSON-схемою та делегування роботи звичайним domain-діям.

16

Вакансії за темою

Backend Developer (PHP, Laravel)

Laravel Офіс B2B Middle $550 - $1,700

Senior Full-Stack розробник з акцентом на backend для розробки веб-системи військової логістики. Робота з Laravel 12, PHP 8.4, Vue.js 3, PostgreSQL/MySQL. Вимоги: 5+ років досвіду веброзробки, глибокі знання архітектури, SOLID/DDD, масштабованих API, CI/CD, Docker, SQL-оптимізація. Очікується технічне лідерство, участь у архітектурних рішеннях і наставництво для команди.

Пакети за темою

Aimeos Laravel

aimeos/aimeos-laravel

Cloud-native, API-first Laravel пакет для електронної комерції з інтегрованою штучною інтелектуальністю для надшвидких онлайн-магазинів, маркетплейсів та складних B2B проектів.

8,702 2026.10.1 13 11

Laravel Query Builder

spatie/laravel-query-builder

Легко будуйте Eloquent-запити на основі запитів від API.

4,472 7.3.5 13 11