Як відхиляти неочікувані ключі масиву за допомогою Laravel Validation

Перекладено ШІ 0 Laravel News 08 серпня, 2026

Laravel 13.24 впроваджує правило `array_keys`, яке допомагає уникнути прихованих помилок через неправильні назви полів у запитах. Тепер ви можете легко обмежити перелік дозволених ключів масиву та отримувати чіткі повідомлення про кожен зайвий параметр.

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

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

# Правило

Працює як об'єктний, так і рядковий синтаксис:

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.

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

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

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

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

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

Правило пропонує два плейсхолдери. :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 таке кастомне повідомлення варте зусиль.

# Приклад використання в ендпоінті

Поєднаємо все в одному FormRequest для маршруту, який приймає фільтрацію, сортування та вкладені зв'язки:

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-колонок

Це правило також корисне при записі даних, наприклад, коли колонка з налаштуваннями (settings/preferences) починає накопичувати зайвий непотріб із фронтенду:

'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'])],

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

# Важливі деталі

Декілька нюансів, які не очевидні з повідомлення про помилку:

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

  • Правило вимагає хоча б один ключ. Виклик 'array_keys' без параметрів викличе InvalidArgumentException під час виконання валідації. Для заборони будь-яких ключів використовуйте правило prohibited.

  • Ключі можуть бути будь-яким об'єктом Arrayable. Можна передавати колекції або списки Enum (валідуються їхні значення):

    Rule::arrayKeys(FilterKey::cases());
    Rule::arrayKeys(collect(config('filters.allowed')));
  • Підтримка варіативної форми. Запис Rule::arrayKeys('status', 'author') ідентичний передачі масиву, що зручно при написанні коду в один рядок.

Правило було додано розробником @nebarg у PR #60918.

# Що ще почитати

Популярні

Інше, що варто прочитати

27 Оновлено 26 червня, 2026

"SQLSTATE[HY000] [2002] Connection refused" у Laravel в GitHub Actions

Чи стикалися ви з помилкою «SQLSTATE[HY000] [2002] Connection refused» під час налаштування GitHub Actions для вашого додатку на Laravel? У нашій статті ми розглянемо три поширені причини цієї помилки та надамо рішення для їх усунення. Читайте далі, щоб дізнатися, як ваш CI/CD потік може працювати бездоганно!

14 Оновлено 26 червня, 2026

Локальні моделі та їх скоупи в Laravel за допомогою атрибута Scope

В Laravel 12 ми отримали можливість використовувати новий підхід для визначення локальних скоупів у моделях Eloquent. Дізнайтеся, як новий атрибут #[Scope] спрощує цей процес і зберігає ваші назви методів незмінними

19 Оновлено 26 червня, 2026

Оптимізація запитів до бази даних за допомогою скорочених методів Laravel

Laravel пропонує зручні методи для роботи з датами, які значно спрощують запити до бази даних. Досліджуйте, як ці інтуїтивно зрозумілі функції допомагають створювати чіткі та зрозумілі умови для роботи з часовими даними!