Идёт обновление сайта. Несколько дней возможны сбои в оформлении и переводах. Документация работает — если страница выглядит сломанной, обновите её позже.

Документация
L Laravel L intervention/image
Войти
Главная Laravel 10.x Валидация

Валидация

10.x 7 мар 2026 г.

#Введение

Laravel предоставляет несколько различных способов для валидации входящих данных вашего приложения. Наиболее часто используется метод validate, доступный во всех входящих HTTP-запросах. Однако мы также рассмотрим и другие подходы к валидации.

Laravel включает широкий набор удобных правил валидации, которые вы можете применять к данным, включая возможность проверки уникальности значений в заданной таблице базы данных. Мы подробно рассмотрим каждое из этих правил, чтобы вы хорошо понимали все возможности валидации в Laravel.

#Быстрый старт с валидацией

Чтобы познакомиться с мощными возможностями валидации Laravel, рассмотрим полный пример валидации формы и отображения сообщений об ошибках пользователю. Из этого обзора вы получите общее представление о том, как валидировать входящие данные запросов с помощью Laravel:

#Определение маршрутов

Сначала предположим, что в файле routes/web.php определены следующие маршруты:

use App\Http\Controllers\PostController;

Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);

Маршрут GET будет отображать форму для создания нового блога, а маршрут POST сохранит новый блог в базе данных.

#Создание контроллера

Далее рассмотрим простой контроллер, который обрабатывает входящие запросы к этим маршрутам. Пока оставим метод store пустым:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class PostController extends Controller
{
    /**
     * Показать форму создания нового блога.
     */
    public function create(): View
    {
        return view('post.create');
    }

    /**
     * Сохранить новый блог.
     */
    public function store(Request $request): RedirectResponse
    {
        // Валидировать и сохранить блог...

        $post = /** ... */

        return to_route('post.show', ['post' => $post->id]);
    }
}

#Написание логики валидации

Теперь мы готовы заполнить метод store логикой валидации нового блога. Для этого используем метод validate, предоставляемый объектом Illuminate\Http\Request. Если правила валидации пройдены, выполнение кода продолжится как обычно; если валидация не пройдет, будет выброшено исключение Illuminate\Validation\ValidationException, и пользователю автоматически отправится соответствующий ответ с ошибкой.

Если валидация не прошла при традиционном HTTP-запросе, будет сгенерирован ответ с перенаправлением на предыдущий URL. Если входящий запрос является XHR-запросом, будет возвращён JSON-ответ с сообщениями об ошибках валидации.

Чтобы лучше понять метод validate, вернёмся к методу store:

/**
 * Сохранить новый блог.
 */
public function store(Request $request): RedirectResponse
{
    $validated = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // Блог валиден...

    return redirect('/posts');
}

Как видите, правила валидации передаются в метод validate. Не волнуйтесь — все доступные правила валидации задокументированы. Если валидация не пройдёт, будет автоматически сгенерирован соответствующий ответ. Если валидация успешна, контроллер продолжит выполнение как обычно.

В качестве альтернативы правила валидации можно указать в виде массива правил вместо одной строки с разделителем |:

$validatedData = $request->validate([
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

Кроме того, вы можете использовать метод validateWithBag для валидации запроса и сохранения сообщений об ошибках в именованном наборе ошибок:

$validatedData = $request->validateWithBag('post', [
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

#Остановка при первой ошибке валидации

Иногда нужно прекратить проверку правил для атрибута после первой ошибки валидации. Для этого добавьте правило bail к атрибуту:

$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);

В этом примере, если правило unique для атрибута title не пройдёт, правило max проверяться не будет. Правила валидируются в порядке их указания.

#Примечание о вложенных атрибутах

Если входящий HTTP-запрос содержит "вложенные" поля, вы можете указать их в правилах валидации с помощью синтаксиса "dot":

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'author.name' => 'required',
    'author.description' => 'required',
]);

Если же имя поля содержит буквальную точку, вы можете явно предотвратить её интерпретацию как синтаксиса "dot", экранировав точку обратным слэшем:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'v1\.0' => 'required',
]);

#Отображение ошибок валидации

Что произойдёт, если поля входящего запроса не пройдут заданные правила валидации? Как уже упоминалось, Laravel автоматически перенаправит пользователя обратно на предыдущую страницу. Кроме того, все ошибки валидации и входные данные запроса будут автоматически сохранены в сессии.

Переменная $errors доступна во всех представлениях вашего приложения благодаря middleware Illuminate\View\Middleware\ShareErrorsFromSession, который входит в группу middleware web. Когда это middleware применяется, переменная $errors всегда будет доступна в представлениях, поэтому можно безопасно предполагать, что $errors определена и использовать её. Переменная $errors будет экземпляром Illuminate\Support\MessageBag. Подробнее о работе с этим объектом см. документацию.

В нашем примере, при ошибках валидации пользователь будет перенаправлен к методу create контроллера, что позволит отобразить сообщения об ошибках в представлении:

<!-- /resources/views/post/create.blade.php -->

<h1>Create Post</h1>

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

<!-- Форма создания поста -->

#Настройка сообщений об ошибках

Встроенные правила валидации Laravel имеют сообщения об ошибках, расположенные в файле lang/en/validation.php вашего приложения. Если у вашего приложения нет директории lang, вы можете создать её с помощью Artisan-команды lang:publish.

В файле lang/en/validation.php вы найдёте запись для каждого правила валидации. Вы можете изменять эти сообщения в соответствии с требованиями вашего приложения.

Кроме того, вы можете скопировать этот файл в другую языковую директорию для перевода сообщений на язык вашего приложения. Чтобы узнать больше о локализации в Laravel, ознакомьтесь с полной документацией по локализации.

Внимание

По умолчанию в скелете приложения Laravel отсутствует директория lang. Если вы хотите настроить языковые файлы Laravel, вы можете опубликовать их с помощью Artisan-команды lang:publish.

#XHR-запросы и валидация

В этом примере мы использовали традиционную форму для отправки данных в приложение. Однако многие приложения получают XHR-запросы с фронтенда на JavaScript. При использовании метода validate в XHR-запросе Laravel не будет генерировать ответ с перенаправлением. Вместо этого Laravel сформирует JSON-ответ со всеми ошибками валидации. Этот JSON-ответ будет отправлен с HTTP-статусом 422.

#Директива @error

Вы можете использовать директиву @error Blade для быстрого определения наличия сообщений об ошибках валидации для заданного атрибута. Внутри директивы @error можно вывести переменную $message для отображения сообщения об ошибке:

<!-- /resources/views/post/create.blade.php -->

<label for="title">Post Title</label>

<input id="title"
    type="text"
    name="title"
    class="@error('title') is-invalid @enderror">

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

Если вы используете именованные наборы ошибок, вы можете передать имя набора ошибок вторым аргументом в директиву @error:

<input ... class="@error('title', 'post') is-invalid @enderror">

#Повторное заполнение форм

Когда Laravel генерирует ответ с перенаправлением из-за ошибки валидации, фреймворк автоматически сохраняет все входные данные запроса в сессии. Это сделано для удобного доступа к этим данным при следующем запросе и повторного заполнения формы, которую пользователь пытался отправить.

Чтобы получить сохранённые данные из предыдущего запроса, вызовите метод old у экземпляра Illuminate\Http\Request. Метод old извлечёт ранее сохранённые данные из сессии:

$title = $request->old('title');

Laravel также предоставляет глобальный помощник old. Если вы отображаете старые данные в Blade-шаблоне, удобнее использовать помощник old для повторного заполнения формы. Если для данного поля нет старых данных, будет возвращено null:

<input type="text" name="title" value="{{ old('title') }}">

#Примечание об необязательных полях

По умолчанию Laravel включает middleware TrimStrings и ConvertEmptyStringsToNull в глобальный стек middleware вашего приложения. Эти middleware перечислены в стеке класса App\Http\Kernel. Из-за этого часто необходимо помечать "необязательные" поля запроса как nullable, если вы не хотите, чтобы валидатор считал null недопустимым значением. Например:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
    'publish_at' => 'nullable|date',
]);

В этом примере мы указываем, что поле publish_at может быть либо null, либо корректной датой. Если модификатор nullable не добавлен, валидатор будет считать null недопустимой датой.

#Формат ответа с ошибками валидации

Когда ваше приложение выбрасывает исключение Illuminate\Validation\ValidationException и входящий HTTP-запрос ожидает JSON-ответ, Laravel автоматически форматирует сообщения об ошибках и возвращает HTTP-ответ с кодом 422 Unprocessable Entity.

Ниже приведён пример формата JSON-ответа с ошибками валидации. Обратите внимание, что вложенные ключи ошибок преобразуются в формат с "dot" нотацией:

{
    "message": "The team name must be a string. (and 4 more errors)",
    "errors": {
        "team_name": [
            "The team name must be a string.",
            "The team name must be at least 1 characters."
        ],
        "authorization.role": [
            "The selected authorization.role is invalid."
        ],
        "users.0.email": [
            "The users.0.email field is required."
        ],
        "users.2.email": [
            "The users.2.email must be a valid email address."
        ]
    }
}

#Валидация с помощью Form Request

#Создание Form Request

Для более сложных сценариев валидации вы можете создать "form request" — пользовательский класс запроса, который инкапсулирует собственную логику валидации и авторизации. Для создания класса form request используйте Artisan-команду make:request:

php artisan make:request StorePostRequest

Сгенерированный класс form request будет помещён в директорию app/Http/Requests. Если этой директории нет, она будет создана при выполнении команды make:request. Каждый form request, созданный Laravel, содержит два метода: authorize и rules.

Как вы могли догадаться, метод authorize отвечает за определение, может ли текущий аутентифицированный пользователь выполнить действие, представленное запросом, а метод rules возвращает правила валидации, которые должны применяться к данным запроса:

/**
 * Получить правила валидации, применимые к запросу.
 *
 * @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
 */
public function rules(): array
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}
Примечание

Вы можете указывать любые зависимости в сигнатуре метода rules. Они будут автоматически разрешены через service container Laravel.

Итак, как оцениваются правила валидации? Всё, что нужно — указать form request в типе параметра метода контроллера. Входящий form request валидируется до вызова метода контроллера, поэтому вам не нужно загромождать контроллер логикой валидации:

/**
 * Сохранить новый блог.
 */
public function store(StorePostRequest $request): RedirectResponse
{
    // Входящий запрос валиден...

    // Получить проверенные данные...
    $validated = $request->validated();

    // Получить часть проверенных данных...
    $validated = $request->safe()->only(['name', 'email']);
    $validated = $request->safe()->except(['name', 'email']);

    // Сохранить блог...

    return redirect('/posts');
}

Если валидация не пройдена, будет сгенерирован ответ с перенаправлением пользователя обратно на предыдущую страницу. Ошибки также будут сохранены в сессии для отображения. Если запрос был XHR, пользователю будет возвращён HTTP-ответ с кодом 422, включающий JSON-представление ошибок валидации.

Примечание

Нужно добавить валидацию form request в реальном времени для вашего фронтенда на Inertia? Ознакомьтесь с Laravel Precognition.

#Выполнение дополнительной валидации

Иногда требуется выполнить дополнительную валидацию после завершения основной. Это можно сделать с помощью метода after form request.

Метод after должен возвращать массив вызываемых функций или замыканий, которые будут вызваны после завершения валидации. Переданные функции получат экземпляр Illuminate\Validation\Validator, что позволит при необходимости добавить дополнительные сообщения об ошибках:

use Illuminate\Validation\Validator;

/**
 * Получить вызываемые функции "after" для валидации запроса.
 */
public function after(): array
{
    return [
        function (Validator $validator) {
            if ($this->somethingElseIsInvalid()) {
                $validator->errors()->add(
                    'field',
                    'С этим полем что-то не так!'
                );
            }
        }
    ];
}

Как отмечалось, массив, возвращаемый методом after, может также содержать вызываемые классы. Метод __invoke этих классов получит экземпляр Illuminate\Validation\Validator:

use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;
use Illuminate\Validation\Validator;

/**
 * Получить вызываемые функции "after" для валидации запроса.
 */
public function after(): array
{
    return [
        new ValidateUserStatus,
        new ValidateShippingTime,
        function (Validator $validator) {
            //
        }
    ];
}

#Остановка при первой ошибке валидации

Добавив свойство stopOnFirstFailure в ваш класс запроса, вы можете указать валидатору прекратить проверку всех атрибутов после первой ошибки валидации:

/**
 * Указывает, должен ли валидатор остановиться при первой ошибке правила.
 *
 * @var bool
 */
protected $stopOnFirstFailure = true;

#Настройка места перенаправления

Как уже обсуждалось, при ошибках валидации form request генерируется ответ с перенаправлением пользователя обратно на предыдущую страницу. Однако вы можете настроить это поведение. Для этого определите свойство $redirect в вашем form request:

/**
 * URI, на который следует перенаправлять пользователей при ошибках валидации.
 *
 * @var string
 */
protected $redirect = '/dashboard';

Или, если вы хотите перенаправлять пользователей на именованный маршрут, определите свойство $redirectRoute:

/**
 * Маршрут, на который следует перенаправлять пользователей при ошибках валидации.
 *
 * @var string
 */
protected $redirectRoute = 'dashboard';

#Авторизация Form Request

Класс form request также содержит метод authorize. В этом методе вы можете определить, имеет ли аутентифицированный пользователь право выполнить обновление ресурса. Например, проверить, принадлежит ли пользователю комментарий блога, который он пытается изменить. Скорее всего, вы будете использовать authorization gates и policies внутри этого метода:

use App\Models\Comment;

/**
 * Определить, авторизован ли пользователь для выполнения этого запроса.
 */
public function authorize(): bool
{
    $comment = Comment::find($this->route('comment'));

    return $comment && $this->user()->can('update', $comment);
}

Поскольку все form request наследуются от базового класса запроса Laravel, мы можем использовать метод user для доступа к текущему аутентифицированному пользователю. Также обратите внимание на вызов метода route в примере выше. Этот метод позволяет получить параметры URI, определённые в вызываемом маршруте, например параметр {comment} в примере ниже:

Route::post('/comment/{comment}');

Если ваше приложение использует route model binding, ваш код может быть ещё короче, получая разрешённую модель как свойство запроса:

return $this->user()->can('update', $this->comment);

Если метод authorize возвращает false, автоматически будет возвращён HTTP-ответ с кодом 403, и метод контроллера не выполнится.

Если вы планируете обрабатывать логику авторизации запроса в другом месте приложения, вы можете полностью удалить метод authorize или просто вернуть true:

/**
 * Определить, авторизован ли пользователь для выполнения этого запроса.
 */
public function authorize(): bool
{
    return true;
}
Примечание

Вы можете указывать любые зависимости в сигнатуре метода authorize. Они будут автоматически разрешены через service container Laravel.

#Настройка сообщений об ошибках

Вы можете настроить сообщения об ошибках, используемые form request, переопределив метод messages. Этот метод должен возвращать массив пар атрибут / правило и соответствующих сообщений об ошибках:

/**
 * Получить сообщения об ошибках для определённых правил валидации.
 *
 * @return array<string, string>
 */
public function messages(): array
{
    return [
        'title.required' => 'Требуется заголовок',
        'body.required' => 'Требуется сообщение',
    ];
}

#Настройка атрибутов валидации

Многие встроенные сообщения об ошибках правил валидации Laravel содержат плейсхолдер :attribute. Если вы хотите, чтобы плейсхолдер :attribute в сообщении заменялся на пользовательское имя атрибута, вы можете указать эти имена, переопределив метод attributes. Этот метод должен возвращать массив пар атрибут / имя:

/**
 * Получить пользовательские имена атрибутов для ошибок валидатора.
 *
 * @return array<string, string>
 */
public function attributes(): array
{
    return [
        'email' => 'адрес электронной почты',
    ];
}

#Подготовка данных для валидации

Если вам нужно подготовить или очистить данные из запроса перед применением правил валидации, используйте метод prepareForValidation:

use Illuminate\Support\Str;

/**
 * Подготовить данные для валидации.
 */
protected function prepareForValidation(): void
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

Аналогично, если нужно нормализовать данные запроса после успешной валидации, используйте метод passedValidation:

/**
 * Обработать успешную валидацию.
 */
protected function passedValidation(): void
{
    $this->replace(['name' => 'Taylor']);
}

#Ручное создание валидаторов

Если вы не хотите использовать метод validate у запроса, можно создать экземпляр валидатора вручную, используя Validator фасад. Метод make на фасаде создаёт новый экземпляр валидатора:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PostController extends Controller
{
    /**
     * Сохранить новый блог.
     */
    public function store(Request $request): RedirectResponse
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // Получить проверенные данные...
        $validated = $validator->validated();

        // Получить часть проверенных данных...
        $validated = $validator->safe()->only(['name', 'email']);
        $validated = $validator->safe()->except(['name', 'email']);

        // Сохранить блог...

        return redirect('/posts');
    }
}

Первым аргументом, передаваемым методу make, являются данные для валидации. Вторым аргументом — массив правил валидации, которые должны применяться к этим данным.

После проверки, провалилась ли валидация запроса, вы можете использовать метод withErrors, чтобы записать сообщения об ошибках в сессию. При использовании этого метода переменная $errors автоматически будет доступна в ваших представлениях после перенаправления, что позволяет легко отобразить их пользователю. Метод withErrors принимает валидатор, MessageBag или PHP array.

#Остановка при первой ошибке валидации

Метод stopOnFirstFailure сообщает валидатору, что он должен прекратить проверку всех атрибутов, как только произойдет первая ошибка валидации:

if ($validator->stopOnFirstFailure()->fails()) {
    // ...
}

#Автоматический редирект

Если вы хотите создать экземпляр валидатора вручную, но при этом воспользоваться автоматическим редиректом, который предоставляет метод validate HTTP-запроса, вы можете вызвать метод validate у существующего экземпляра валидатора. Если валидация не пройдет, пользователь будет автоматически перенаправлен или, в случае XHR-запроса, будет возвращён JSON-ответ:

Validator::make($request->all(), [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
])->validate();

Вы можете использовать метод validateWithBag для сохранения сообщений об ошибках в именованном наборе ошибок, если валидация не пройдет:

Validator::make($request->all(), [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
])->validateWithBag('post');

#Именованные наборы ошибок

Если на одной странице у вас несколько форм, вы можете присвоить имя MessageBag, содержащему ошибки валидации, чтобы получать сообщения об ошибках для конкретной формы. Для этого передайте имя вторым аргументом в метод withErrors:

return redirect('register')->withErrors($validator, 'login');

Затем вы можете получить доступ к именованному экземпляру MessageBag через переменную $errors:

{{ $errors->login->first('email') }}

#Настройка сообщений об ошибках

При необходимости вы можете задать собственные сообщения об ошибках, которые валидатор будет использовать вместо стандартных сообщений Laravel. Существует несколько способов указать кастомные сообщения. Во-первых, вы можете передать их третьим аргументом в метод Validator::make:

$validator = Validator::make($input, $rules, $messages = [
    'required' => 'Поле :attribute обязательно для заполнения.',
]);

В этом примере плейсхолдер :attribute будет заменён на фактическое имя поля, которое проверяется. Вы также можете использовать другие плейсхолдеры в сообщениях валидации. Например:

$messages = [
    'same' => 'Поля :attribute и :other должны совпадать.',
    'size' => 'Поле :attribute должно быть ровно :size.',
    'between' => 'Значение поля :attribute (:input) должно быть между :min и :max.',
    'in' => 'Поле :attribute должно быть одним из следующих типов: :values',
];

#Указание кастомного сообщения для конкретного атрибута

Иногда нужно задать сообщение об ошибке только для конкретного атрибута. Это можно сделать с помощью "dot" нотации. Сначала укажите имя атрибута, затем правило:

$messages = [
    'email.required' => 'Нам нужен ваш адрес электронной почты!',
];

#Указание пользовательских значений атрибутов

Многие встроенные сообщения об ошибках Laravel содержат плейсхолдер :attribute, который заменяется именем поля или атрибута, проходящего валидацию. Чтобы настроить значения, которые будут подставляться вместо этих плейсхолдеров для конкретных полей, вы можете передать массив пользовательских атрибутов четвёртым аргументом в метод Validator::make:

$validator = Validator::make($input, $rules, $messages, [
    'email' => 'адрес электронной почты',
]);

#Выполнение дополнительной валидации

Иногда требуется выполнить дополнительную валидацию после завершения основной проверки. Это можно сделать с помощью метода after валидатора. Метод after принимает замыкание или массив вызываемых функций, которые будут вызваны после завершения валидации. Переданные функции получат экземпляр Illuminate\Validation\Validator, что позволит добавить дополнительные сообщения об ошибках при необходимости:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make(/* ... */);

$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add(
            'field', 'С этим полем что-то не так!'
        );
    }
});

if ($validator->fails()) {
    // ...
}

Как отмечалось, метод after также принимает массив вызываемых функций, что особенно удобно, если ваша логика "после валидации" инкапсулирована в вызываемых классах, которые получат экземпляр Illuminate\Validation\Validator через метод __invoke:

use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;

$validator->after([
    new ValidateUserStatus,
    new ValidateShippingTime,
    function ($validator) {
        // ...
    },
]);

#Работа с проверенными данными

После валидации входящих данных запроса с помощью form request или вручную созданного экземпляра валидатора, вы можете захотеть получить именно те данные, которые прошли проверку. Это можно сделать несколькими способами. Во-первых, можно вызвать метод validated у form request или валидатора. Этот метод возвращает массив проверенных данных:

$validated = $request->validated();

$validated = $validator->validated();

Альтернативно, можно вызвать метод safe у form request или валидатора. Этот метод возвращает экземпляр Illuminate\Support\ValidatedInput. Этот объект предоставляет методы only, except и all для получения части проверенных данных или всего массива проверенных данных:

$validated = $request->safe()->only(['name', 'email']);

$validated = $request->safe()->except(['name', 'email']);

$validated = $request->safe()->all();

Кроме того, экземпляр Illuminate\Support\ValidatedInput можно перебирать и использовать как массив:

// Проверенные данные можно перебирать...
foreach ($request->safe() as $key => $value) {
    // ...
}

// Проверенные данные можно использовать как массив...
$validated = $request->safe();

$email = $validated['email'];

Если вы хотите добавить дополнительные поля к проверенным данным, можно вызвать метод merge:

$validated = $request->safe()->merge(['name' => 'Taylor Otwell']);

Если вы хотите получить проверенные данные в виде экземпляра collection, можно вызвать метод collect:

$collection = $request->safe()->collect();

#Работа с сообщениями об ошибках

После вызова метода errors у экземпляра Validator вы получите объект Illuminate\Support\MessageBag, который содержит множество удобных методов для работы с сообщениями об ошибках. Переменная $errors, автоматически доступная во всех представлениях, также является экземпляром класса MessageBag.

#Получение первого сообщения об ошибке для поля

Чтобы получить первое сообщение об ошибке для конкретного поля, используйте метод first:

$errors = $validator->errors();

echo $errors->first('email');

#Получение всех сообщений об ошибках для поля

Если нужно получить массив всех сообщений для конкретного поля, используйте метод get:

foreach ($errors->get('email') as $message) {
    // ...
}

Если вы валидируете поле формы, являющееся массивом, можно получить все сообщения для каждого элемента массива, используя символ *:

foreach ($errors->get('attachments.*') as $message) {
    // ...
}

#Получение всех сообщений об ошибках для всех полей

Чтобы получить массив всех сообщений для всех полей, используйте метод all:

foreach ($errors->all() as $message) {
    // ...
}

#Проверка наличия сообщений для поля

Метод has позволяет определить, существуют ли сообщения об ошибках для конкретного поля:

if ($errors->has('email')) {
    // ...
}

#Указание кастомных сообщений в языковых файлах

Встроенные правила валидации Laravel имеют сообщения об ошибках, расположенные в файле lang/en/validation.php вашего приложения. Если в вашем приложении отсутствует директория lang, вы можете создать её с помощью Artisan-команды lang:publish.

В файле lang/en/validation.php вы найдете запись перевода для каждого правила валидации. Вы можете изменять или настраивать эти сообщения в соответствии с требованиями вашего приложения.

Кроме того, вы можете скопировать этот файл в другую языковую директорию для перевода сообщений на язык вашего приложения. Подробнее о локализации Laravel читайте в полном руководстве по локализации.

Внимание

По умолчанию в скелете приложения Laravel отсутствует директория lang. Если вы хотите настроить языковые файлы Laravel, вы можете опубликовать их с помощью Artisan-команды lang:publish.

#Кастомные сообщения для конкретных атрибутов

Вы можете настроить сообщения об ошибках для определённых комбинаций атрибутов и правил в языковых файлах валидации вашего приложения. Для этого добавьте ваши настройки сообщений в массив custom файла lang/xx/validation.php вашего приложения:

'custom' => [
    'email' => [
        'required' => 'Нам нужен ваш адрес электронной почты!',
        'max' => 'Ваш адрес электронной почты слишком длинный!'
    ],
],

#Указание атрибутов в языковых файлах

Многие встроенные сообщения об ошибках Laravel содержат плейсхолдер :attribute, который заменяется именем поля или атрибута, проходящего валидацию. Если вы хотите, чтобы часть :attribute в сообщении заменилась на пользовательское значение, вы можете указать пользовательское имя атрибута в массиве attributes файла lang/xx/validation.php:

'attributes' => [
    'email' => 'адрес электронной почты',
],
Внимание

По умолчанию в скелете приложения Laravel отсутствует директория lang. Если вы хотите настроить языковые файлы Laravel, вы можете опубликовать их с помощью Artisan-команды lang:publish.

#Указание значений в языковых файлах

Некоторые встроенные сообщения об ошибках правил валидации Laravel содержат плейсхолдер :value, который заменяется текущим значением атрибута запроса. Однако иногда требуется, чтобы часть :value в сообщении заменялась на пользовательское представление значения. Например, рассмотрим правило, которое требует номер кредитной карты, если payment_type имеет значение cc:

Validator::make($request->all(), [
    'credit_card_number' => 'required_if:payment_type,cc'
]);

Если это правило валидации не пройдет, будет выведено следующее сообщение об ошибке:

The credit card number field is required when payment type is cc.

Вместо отображения cc как значения типа оплаты, вы можете указать более удобочитаемое представление значения в вашем файле lang/xx/validation.php, определив массив values:

'values' => [
    'payment_type' => [
        'cc' => 'кредитная карта'
    ],
],
Внимание

По умолчанию в скелете приложения Laravel отсутствует директория lang. Если вы хотите настроить языковые файлы Laravel, вы можете опубликовать их с помощью Artisan-команды lang:publish.

После определения этого значения правило валидации будет выдавать следующее сообщение об ошибке:

The credit card number field is required when payment type is credit card.

#Доступные правила валидации

Ниже приведён список всех доступных правил валидации и их описание:

<style> .collection-method-list > p { columns: 10.8em 3; -moz-columns: 10.8em 3; -webkit-columns: 10.8em 3; } .collection-method-list a { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } </style>

#accepted

Поле, проходящее валидацию, должно иметь значение "yes", "on", 1, "1", true или "true". Это полезно для проверки согласия с "Условиями использования" или аналогичных полей.

#accepted_if:anotherfield,value,...

Поле, проходящее валидацию, должно иметь значение "yes", "on", 1, "1", true или "true", если другое поле валидации равно указанному значению. Это полезно для проверки согласия с "Условиями использования" или аналогичных полей.

#active_url

Поле, проходящее валидацию, должно иметь действительную запись A или AAAA согласно функции PHP dns_get_record. Имя хоста из предоставленного URL извлекается с помощью функции PHP parse_url перед передачей в dns_get_record.

#after:date

Поле, проходящее валидацию, должно быть датой после указанной даты. Даты будут переданы в функцию PHP strtotime для преобразования в валидный экземпляр DateTime:

'start_date' => 'required|date|after:tomorrow'

Вместо передачи строки с датой для обработки strtotime, вы можете указать другое поле для сравнения с датой:

'finish_date' => 'required|date|after:start_date'

#after_or_equal:date

Поле, проходящее валидацию, должно быть датой после или равной указанной дате. Подробнее смотрите правило after.

#alpha

Поле, проходящее валидацию, должно содержать только символы Unicode из алфавита, входящие в наборы \p{L} и \p{M}.

Чтобы ограничить это правило символами из ASCII (a-z и A-Z), вы можете добавить опцию ascii к правилу валидации:

'username' => 'alpha:ascii',

#alpha_dash

Поле, проходящее валидацию, должно содержать только символы Unicode из алфавита и цифр, входящие в наборы \p{L}, \p{M}, \p{N}, а также ASCII дефисы (-) и подчеркивания (_).

Чтобы ограничить это правило символами из ASCII (a-z и A-Z), вы можете добавить опцию ascii к правилу валидации:

'username' => 'alpha_dash:ascii',

#alpha_num

Поле, проходящее валидацию, должно содержать только символы Unicode из алфавита и цифр, входящие в наборы \p{L}, \p{M}, и \p{N}.

Чтобы ограничить это правило символами из ASCII (a-z и A-Z), вы можете добавить опцию ascii к правилу валидации:

'username' => 'alpha_num:ascii',

#array

Поле, проходящее валидацию, должно быть PHP array.

Если к правилу array добавлены дополнительные значения, каждый ключ во входном массиве должен присутствовать в списке значений, переданных правилу. В следующем примере ключ admin во входном массиве недопустим, так как он отсутствует в списке значений правила array:

use Illuminate\Support\Facades\Validator;

$input = [
    'user' => [
        'name' => 'Taylor Otwell',
        'username' => 'taylorotwell',
        'admin' => true,
    ],
];

Validator::make($input, [
    'user' => 'array:name,username',
]);

В общем случае всегда следует указывать ключи массива, которые разрешены в вашем массиве.

#ascii

Поле, проходящее валидацию, должно содержать только 7-битные ASCII символы.

#bail

Прекратить выполнение правил валидации для поля после первой ошибки.

В то время как правило bail останавливает валидацию только для конкретного поля при первой ошибке, метод stopOnFirstFailure сообщает валидатору, что он должен прекратить проверку всех атрибутов при первой же ошибке:

if ($validator->stopOnFirstFailure()->fails()) {
    // ...
}

#before:date

Поле, проходящее валидацию, должно быть датой, предшествующей указанной дате. Даты будут переданы в функцию PHP strtotime для преобразования в валидный экземпляр DateTime. Кроме того, как и в правиле after, в качестве значения date может быть указано имя другого поля валидации.

#before_or_equal:date

Поле, проходящее валидацию, должно быть датой, предшествующей или равной указанной дате. Даты будут переданы в функцию PHP strtotime для преобразования в валидный экземпляр DateTime. Кроме того, как и в правиле after, в качестве значения date может быть указано имя другого поля валидации.

#between:min,max

Поле, проходящее валидацию, должно иметь размер между заданными min и max (включительно). Строки, числа, массивы и файлы оцениваются так же, как в правиле size.

#boolean

Поле, проходящее валидацию, должно быть приводимым к булевому типу. Допустимые значения: true, false, 1, 0, "1" и "0".

#confirmed

Поле, проходящее валидацию, должно иметь соответствующее поле с именем {field}_confirmation. Например, если поле называется password, должен присутствовать password_confirmation.

#current_password

Поле, проходящее валидацию, должно совпадать с паролем аутентифицированного пользователя. Вы можете указать guard аутентификации в первом параметре правила:

'password' => 'current_password:api'

#date

Поле, проходящее валидацию, должно быть допустимой датой без относительных значений согласно функции PHP strtotime.

#date_equals:date

Поле, проходящее валидацию, должно быть равно указанной дате. Даты будут переданы в функцию PHP strtotime для преобразования в валидный экземпляр DateTime.

#date_format:format,...

Поле, проходящее валидацию, должно соответствовать одному из указанных форматов. При валидации поля следует использовать либо date, либо date_format, но не оба одновременно. Это правило поддерживает все форматы, поддерживаемые классом PHP DateTime.

#decimal:min,max

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

// Должно иметь ровно два десятичных знака (9.99)...
'price' => 'decimal:2'

// Должно иметь от 2 до 4 десятичных знаков...
'price' => 'decimal:2,4'

#declined

Поле, проходящее валидацию, должно иметь значение "no", "off", 0, "0", false или "false".

#declined_if:anotherfield,value,...

Поле, проходящее валидацию, должно иметь значение "no", "off", 0, "0", false или "false", если другое поле валидации равно указанному значению.

#different:field

Поле, проходящее валидацию, должно иметь значение, отличное от значения поля field.

#digits:value

Целое число, проходящее валидацию, должно иметь точную длину value.

#digits_between:min,max

Целое число, проходящее валидацию, должно иметь длину между заданными min и max.

#dimensions

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

'avatar' => 'dimensions:min_width=100,min_height=200'

Доступные ограничения: min_width, max_width, min_height, max_height, width, height, ratio.

Ограничение ratio должно задаваться как отношение ширины к высоте. Это можно указать либо в виде дроби, например 3/2, либо в виде числа с плавающей точкой, например 1.5:

'avatar' => 'dimensions:ratio=3/2'

Поскольку это правило требует нескольких аргументов, вы можете использовать метод Rule::dimensions для удобного построения правила:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'avatar' => [
        'required',
        Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
    ],
]);

#distinct

При валидации массивов поле не должно содержать дублирующихся значений:

'foo.*.id' => 'distinct'

По умолчанию правило distinct использует нестрогое сравнение переменных. Чтобы использовать строгое сравнение, добавьте параметр strict в определение правила:

'foo.*.id' => 'distinct:strict'

Вы можете добавить ignore_case в аргументы правила, чтобы игнорировать различия в регистре:

'foo.*.id' => 'distinct:ignore_case'

#doesnt_start_with:foo,bar,...

Поле, проходящее валидацию, не должно начинаться с одного из указанных значений.

#doesnt_end_with:foo,bar,...

Поле, проходящее валидацию, не должно заканчиваться одним из указанных значений.

#email

Поле, подлежащее валидации, должно быть отформатировано как адрес электронной почты. Это правило валидации использует пакет egulias/email-validator для проверки email-адреса. По умолчанию применяется валидатор RFCValidation, но вы также можете использовать другие стили валидации:

'email' => 'email:rfc,dns'

Пример выше применит валидации RFCValidation и DNSCheckValidation. Вот полный список стилей валидации, которые вы можете использовать:

  • rfc: RFCValidation
  • strict: NoRFCWarningsValidation
  • dns: DNSCheckValidation
  • spoof: SpoofCheckValidation
  • filter: FilterEmailValidation
  • filter_unicode: FilterEmailValidation::unicode()

Валидатор filter, который использует функцию PHP filter_var, поставляется с Laravel и был поведением валидации email по умолчанию до версии Laravel 5.8.

Внимание

Валидаторы dns и spoof требуют расширение PHP intl.

#ends_with:foo,bar,...

Поле, подлежащее валидации, должно заканчиваться одним из указанных значений.

#enum

Правило Enum — это основанное на классе правило, которое проверяет, содержит ли поле под валидацией допустимое значение перечисления (enum). Правило Enum принимает имя enum в качестве единственного аргумента конструктора. При валидации примитивных значений следует передавать в правило Enum поддерживаемый Enum:

use App\Enums\ServerStatus;
use Illuminate\Validation\Rule;

$request->validate([
    'status' => [Rule::enum(ServerStatus::class)],
]);

Методы only и except правила Enum могут использоваться для ограничения допустимых вариантов enum:

Rule::enum(ServerStatus::class)
    ->only([ServerStatus::Pending, ServerStatus::Active]);

Rule::enum(ServerStatus::class)
    ->except([ServerStatus::Pending, ServerStatus::Active]);

Метод when может использоваться для условного изменения правила Enum:

use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;

Rule::enum(ServerStatus::class)
    ->when(
        Auth::user()->isAdmin(),
        fn ($rule) => $rule->only(...),
        fn ($rule) => $rule->only(...),
    );

#exclude

Поле, подлежащее валидации, будет исключено из данных запроса, возвращаемых методами validate и validated.

#exclude_if:anotherfield,value

Поле, подлежащее валидации, будет исключено из данных запроса, возвращаемых методами validate и validated, если поле anotherfield равно value.

Если требуется сложная логика условного исключения, можно использовать метод Rule::excludeIf. Этот метод принимает булево значение или замыкание. При передаче замыкания оно должно возвращать true или false, чтобы указать, следует ли исключить поле из валидации:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => Rule::excludeIf($request->user()->is_admin),
]);

Validator::make($request->all(), [
    'role_id' => Rule::excludeIf(fn () => $request->user()->is_admin),
]);

#exclude_unless:anotherfield,value

Поле, подлежащее валидации, будет исключено из данных запроса, возвращаемых методами validate и validated, если поле anotherfield не равно value. Если value равно null (exclude_unless:name,null), поле будет исключено, если поле сравнения равно null или отсутствует в данных запроса.

#exclude_with:anotherfield

Поле, подлежащее валидации, будет исключено из данных запроса, возвращаемых методами validate и validated, если поле anotherfield присутствует.

#exclude_without:anotherfield

Поле, подлежащее валидации, будет исключено из данных запроса, возвращаемых методами validate и validated, если поле anotherfield отсутствует.

#exists:table,column

Поле, подлежащее валидации, должно существовать в указанной таблице базы данных.

#Основное использование правила Exists

'state' => 'exists:states'

Если опция column не указана, будет использовано имя поля. Таким образом, в данном случае правило проверит, что в таблице states есть запись, где значение столбца state совпадает со значением атрибута state из запроса.

#Указание пользовательского имени столбца

Вы можете явно указать имя столбца базы данных, которое должно использоваться правилом валидации, указав его после имени таблицы:

'state' => 'exists:states,abbreviation'

Иногда может потребоваться указать конкретное соединение с базой данных для запроса exists. Это можно сделать, добавив имя соединения перед именем таблицы:

'email' => 'exists:connection.staff,email'

Вместо указания имени таблицы напрямую, вы можете указать Eloquent-модель, которая будет использоваться для определения имени таблицы:

'user_id' => 'exists:App\Models\User,id'

Если вы хотите настроить выполняемый запрос правила валидации, можно использовать класс Rule для удобного определения правила. В этом примере мы также укажем правила валидации в виде массива вместо использования символа | для разделения:

use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::exists('staff')->where(function (Builder $query) {
            return $query->where('account_id', 1);
        }),
    ],
]);

Вы можете явно указать имя столбца базы данных, которое должно использоваться правилом exists, созданным методом Rule::exists, передав имя столбца вторым аргументом метода exists:

'state' => Rule::exists('states', 'abbreviation'),

#extensions:foo,bar,...

Файл, подлежащий валидации, должен иметь расширение, соответствующее одному из перечисленных:

'photo' => ['required', 'extensions:jpg,png'],
Внимание

Никогда не следует полагаться только на проверку файла по его пользовательскому расширению. Это правило обычно следует использовать вместе с правилами mimes или mimetypes.

#file

Поле, подлежащее валидации, должно быть успешно загруженным файлом.

#filled

Поле, подлежащее валидации, не должно быть пустым, если оно присутствует.

#gt:field

Поле, подлежащее валидации, должно быть больше указанного field или value. Оба поля должны быть одного типа. Строки, числа, массивы и файлы оцениваются по тем же правилам, что и правило size.

#gte:field

Поле, подлежащее валидации, должно быть больше или равно указанному field или value. Оба поля должны быть одного типа. Строки, числа, массивы и файлы оцениваются по тем же правилам, что и правило size.

#hex_color

Поле, подлежащее валидации, должно содержать корректное значение цвета в шестнадцатеричном формате.

#image

Файл, подлежащий валидации, должен быть изображением (jpg, jpeg, png, bmp, gif, svg или webp).

#in:foo,bar,...

Поле, подлежащее валидации, должно входить в указанный список значений. Поскольку это правило часто требует implode массива, для удобного построения правила можно использовать метод Rule::in:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'zones' => [
        'required',
        Rule::in(['first-zone', 'second-zone']),
    ],
]);

Если правило in используется вместе с правилом array, каждое значение во входном массиве должно присутствовать в списке значений, переданных правилу in. В следующем примере код аэропорта LAS во входном массиве недопустим, так как он отсутствует в списке аэропортов, переданных правилу in:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

$input = [
    'airports' => ['NYC', 'LAS'],
];

Validator::make($input, [
    'airports' => [
        'required',
        'array',
    ],
    'airports.*' => Rule::in(['NYC', 'LIT']),
]);

#in_array:anotherfield.*

Поле, подлежащее валидации, должно существовать среди значений поля anotherfield.

#integer

Поле, подлежащее валидации, должно быть целым числом.

Внимание

Это правило валидации не проверяет, что входные данные имеют тип переменной "integer", а лишь то, что они соответствуют правилу PHP FILTER_VALIDATE_INT. Если вам нужно проверить, что входные данные являются числом, используйте это правило вместе с правилом numeric.

#ip

Поле, подлежащее валидации, должно быть IP-адресом.

#ipv4

Поле, подлежащее валидации, должно быть IPv4-адресом.

#ipv6

Поле, подлежащее валидации, должно быть IPv6-адресом.

#json

Поле, подлежащее валидации, должно быть корректной JSON-строкой.

#lt:field

Поле, подлежащее валидации, должно быть меньше указанного field. Оба поля должны быть одного типа. Строки, числа, массивы и файлы оцениваются по тем же правилам, что и правило size.

#lte:field

Поле, подлежащее валидации, должно быть меньше или равно указанному field. Оба поля должны быть одного типа. Строки, числа, массивы и файлы оцениваются по тем же правилам, что и правило size.

#lowercase

Поле, подлежащее валидации, должно быть в нижнем регистре.

#mac_address

Поле, подлежащее валидации, должно быть MAC-адресом.

#max:value

Поле, подлежащее валидации, должно быть меньше или равно максимальному значению value. Строки, числа, массивы и файлы оцениваются так же, как в правиле size.

#max_digits:value

Целое число, подлежащее валидации, должно иметь максимальную длину value.

#mimetypes:text/plain,...

Файл, подлежащий валидации, должен соответствовать одному из указанных MIME-типов:

'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'

Для определения MIME-типа загруженного файла будет прочитано содержимое файла, и фреймворк попытается угадать MIME-тип, который может отличаться от MIME-типа, предоставленного клиентом.

#mimes:foo,bar,...

Файл, подлежащий валидации, должен иметь MIME-тип, соответствующий одному из перечисленных расширений:

'photo' => 'mimes:jpg,bmp,png'

Хотя нужно указать только расширения, это правило фактически проверяет MIME-тип файла, читая его содержимое и угадывая MIME-тип. Полный список MIME-типов и соответствующих им расширений можно найти по адресу:

https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

#MIME-типы и расширения

Это правило валидации не проверяет соответствие между MIME-типом и расширением, назначенным пользователем файлу. Например, правило mimes:png сочтет файл с корректным содержимым PNG допустимым PNG-изображением, даже если файл называется photo.txt. Если вы хотите проверить расширение, назначенное пользователем, используйте правило extensions.

#min:value

Поле, подлежащее валидации, должно иметь минимальное значение value. Строки, числа, массивы и файлы оцениваются так же, как в правиле size.

#min_digits:value

Целое число, подлежащее валидации, должно иметь минимальную длину value.

#multiple_of:value

Поле, подлежащее валидации, должно быть кратно value.

#missing

Поле, подлежащее валидации, не должно присутствовать во входных данных.

#missing_if:anotherfield,value,...

Поле, подлежащее валидации, не должно присутствовать, если поле anotherfield равно любому из значений value.

#missing_unless:anotherfield,value

Поле, подлежащее валидации, не должно присутствовать, если поле anotherfield не равно ни одному из значений value.

#missing_with:foo,bar,...

Поле, подлежащее валидации, не должно присутствовать только если любое из других указанных полей присутствует.

#missing_with_all:foo,bar,...

Поле, подлежащее валидации, не должно присутствовать только если все другие указанные поля присутствуют.

#not_in:foo,bar,...

Поле, подлежащее валидации, не должно входить в указанный список значений. Для удобного построения правила можно использовать метод Rule::notIn:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'toppings' => [
        'required',
        Rule::notIn(['sprinkles', 'cherries']),
    ],
]);

#not_regex:pattern

Поле, подлежащее валидации, не должно соответствовать заданному регулярному выражению.

Внутри правило использует функцию PHP preg_match. Указанный шаблон должен соответствовать формату, требуемому preg_match, включая корректные разделители. Например: 'email' => 'not_regex:/^.+$/i'.

Внимание

При использовании шаблонов regex / not_regex может потребоваться указывать правила в виде массива вместо разделения символом |, особенно если регулярное выражение содержит символ |.

#nullable

Поле, подлежащее валидации, может быть null.

#numeric

Поле, подлежащее валидации, должно быть числовым.

#present

Поле, подлежащее валидации, должно присутствовать во входных данных.

#present_if:anotherfield,value,...

Поле, подлежащее валидации, должно присутствовать, если поле anotherfield равно любому из значений value.

#present_unless:anotherfield,value

Поле, подлежащее валидации, должно присутствовать, если поле anotherfield не равно ни одному из значений value.

#present_with:foo,bar,...

Поле, подлежащее валидации, должно присутствовать только если любое из других указанных полей присутствует.

#present_with_all:foo,bar,...

Поле, подлежащее валидации, должно присутствовать только если все другие указанные поля присутствуют.

#prohibited

Поле, подлежащее валидации, должно отсутствовать или быть пустым. Поле считается "пустым", если выполняется одно из следующих условий:

  • Значение равно null.
  • Значение — пустая строка.
  • Значение — пустой массив или пустой объект, реализующий интерфейс Countable.
  • Значение — загруженный файл с пустым путем.

#prohibited_if:anotherfield,value,...

Поле, подлежащее валидации, должно отсутствовать или быть пустым, если поле anotherfield равно любому из значений value. Поле считается "пустым", если выполняется одно из следующих условий:

  • Значение равно null.
  • Значение — пустая строка.
  • Значение — пустой массив или пустой объект, реализующий интерфейс Countable.
  • Значение — загруженный файл с пустым путем.

Если требуется сложная логика условного запрета, можно использовать метод Rule::prohibitedIf. Этот метод принимает булево значение или замыкание. При передаче замыкания оно должно возвращать true или false, чтобы указать, следует ли запретить поле:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => Rule::prohibitedIf($request->user()->is_admin),
]);

Validator::make($request->all(), [
    'role_id' => Rule::prohibitedIf(fn () => $request->user()->is_admin),
]);

#prohibited_unless:anotherfield,value,...

Поле, подлежащее валидации, должно отсутствовать или быть пустым, если поле anotherfield не равно ни одному из значений value. Поле считается "пустым", если выполняется одно из следующих условий:

  • Значение равно null.
  • Значение — пустая строка.
  • Значение — пустой массив или пустой объект, реализующий интерфейс Countable.
  • Значение — загруженный файл с пустым путем.

#prohibits:anotherfield,...

Если поле, подлежащее валидации, присутствует и не пусто, все поля из anotherfield должны отсутствовать или быть пустыми. Поле считается "пустым", если выполняется одно из следующих условий:

  • Значение равно null.
  • Значение — пустая строка.
  • Значение — пустой массив или пустой объект, реализующий интерфейс Countable.
  • Значение — загруженный файл с пустым путем.

#regex:pattern

Поле, подлежащее валидации, должно соответствовать заданному регулярному выражению.

Внутри правило использует функцию PHP preg_match. Указанный шаблон должен соответствовать формату, требуемому preg_match, включая корректные разделители. Например: 'email' => 'regex:/^.+@.+$/i'.

Внимание

При использовании шаблонов regex / not_regex может потребоваться указывать правила в виде массива вместо разделения символом |, особенно если регулярное выражение содержит символ |.

#required

Поле, подлежащее валидации, должно присутствовать во входных данных и не быть пустым. Поле считается "пустым", если выполняется одно из следующих условий:

  • Значение равно null.
  • Значение — пустая строка.
  • Значение — пустой массив или пустой объект, реализующий интерфейс Countable.
  • Значение — загруженный файл без пути.

#required_if:anotherfield,value,...

Поле, подлежащее валидации, должно присутствовать и не быть пустым, если поле anotherfield равно любому из значений value.

Если вы хотите задать более сложное условие для правила required_if, можно использовать метод Rule::requiredIf. Этот метод принимает булево значение или замыкание. При передаче замыкания оно должно возвращать true или false, чтобы указать, обязательно ли поле для валидации:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => Rule::requiredIf($request->user()->is_admin),
]);

Validator::make($request->all(), [
    'role_id' => Rule::requiredIf(fn () => $request->user()->is_admin),
]);

#required_if_accepted:anotherfield,...

Поле, подлежащее валидации, должно присутствовать и не быть пустым, если поле anotherfield равно "yes", "on", 1, "1", true или "true".

#required_unless:anotherfield,value,...

Поле, подлежащее валидации, должно присутствовать и не быть пустым, если поле anotherfield не равно ни одному из значений value. Это также означает, что поле anotherfield должно присутствовать в данных запроса, если value не равно null. Если value равно null (required_unless:name,null), поле будет обязательным, если поле сравнения не равно null или отсутствует в данных запроса.

#required_with:foo,bar,...

Поле, подлежащее валидации, должно присутствовать и не быть пустым только если любое из других указанных полей присутствует и не пусто.

#required_with_all:foo,bar,...

Поле, подлежащее валидации, должно присутствовать и не быть пустым только если все другие указанные поля присутствуют и не пусты.

#required_without:foo,bar,...

Поле, подлежащее валидации, должно присутствовать и не быть пустым только когда любое из других указанных полей пусто или отсутствует.

#required_without_all:foo,bar,...

Поле, подлежащее валидации, должно присутствовать и не быть пустым только когда все другие указанные поля пусты или отсутствуют.

#required_array_keys:foo,bar,...

Поле, подлежащее валидации, должно быть массивом и содержать как минимум указанные ключи.

#same:field

Указанное поле field должно совпадать с полем, подлежащим валидации.

#size:value

Поле, которое проверяется, должно иметь размер, равный указанному value. Для строковых данных value соответствует количеству символов. Для числовых данных value соответствует целому числу (атрибут также должен иметь правило numeric или integer). Для массива size соответствует count массива. Для файлов size соответствует размеру файла в килобайтах. Рассмотрим примеры:

// Проверить, что строка ровно 12 символов...
'title' => 'size:12';

// Проверить, что целое число равно 10...
'seats' => 'integer|size:10';

// Проверить, что массив содержит ровно 5 элементов...
'tags' => 'array|size:5';

// Проверить, что загруженный файл ровно 512 килобайт...
'image' => 'file|size:512';

#starts_with:foo,bar,...

Поле, подлежащее валидации, должно начинаться с одного из указанных значений.

#string

Поле, подлежащее валидации, должно быть строкой. Если вы хотите разрешить также значение null, следует добавить правило nullable.

#timezone

Поле, подлежащее валидации, должно быть корректным идентификатором часового пояса согласно методу DateTimeZone::listIdentifiers.

Аргументы, принимаемые методом DateTimeZone::listIdentifiers, также могут быть переданы этому правилу валидации:

'timezone' => 'required|timezone:all';

'timezone' => 'required|timezone:Africa';

'timezone' => 'required|timezone:per_country,US';

#unique:table,column

Поле, подлежащее валидации, не должно существовать в указанной таблице базы данных.

Указание пользовательского имени таблицы / столбца:

Вместо указания имени таблицы напрямую, вы можете указать Eloquent-модель, которая будет использоваться для определения имени таблицы:

'email' => 'unique:App\Models\User,email_address'

Опция column может использоваться для указания соответствующего столбца базы данных. Если опция column не указана, будет использовано имя поля, подлежащего валидации.

'email' => 'unique:users,email_address'

Указание пользовательского подключения к базе данных

Иногда может потребоваться задать пользовательское подключение для запросов Validator. Для этого можно добавить имя подключения перед именем таблицы:

'email' => 'unique:connection.users,email_address'

Принудительное игнорирование уникального правила для заданного ID:

Иногда нужно игнорировать определённый ID при проверке уникальности. Например, на экране "обновления профиля", где есть имя пользователя, email и местоположение, вы хотите проверить уникальность email. Но если пользователь меняет только имя, а email остаётся тем же, не должно возникать ошибки валидации, так как пользователь уже владеет этим email.

Чтобы указать валидатору игнорировать ID пользователя, используйте класс Rule для удобного определения правила. В этом примере правила валидации указаны в виде массива вместо разделения символом |:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::unique('users')->ignore($user->id),
    ],
]);
Внимание

Никогда не передавайте в метод ignore данные, контролируемые пользователем. Передавайте только системно сгенерированные уникальные ID, такие как автоинкрементный ID или UUID из экземпляра модели Eloquent. В противном случае ваше приложение будет уязвимо к SQL-инъекциям.

Вместо передачи значения ключа модели в метод ignore, можно передать весь экземпляр модели. Laravel автоматически извлечёт ключ из модели:

Rule::unique('users')->ignore($user)

Если в вашей таблице используется имя первичного ключа, отличное от id, вы можете указать имя столбца при вызове метода ignore:

Rule::unique('users')->ignore($user->id, 'user_id')

По умолчанию правило unique проверяет уникальность столбца с именем атрибута, подлежащего валидации. Однако вы можете передать другое имя столбца вторым аргументом метода unique:

Rule::unique('users', 'email_address')->ignore($user->id)

Добавление дополнительных условий where:

Вы можете указать дополнительные условия запроса, настроив запрос с помощью метода where. Например, добавим условие, ограничивающее поиск записями с account_id, равным 1:

'email' => Rule::unique('users')->where(fn (Builder $query) => $query->where('account_id', 1))

#uppercase

Поле, подлежащее валидации, должно быть в верхнем регистре.

#url

Поле, подлежащее валидации, должно быть корректным URL.

Если вы хотите указать протоколы URL, которые считаются допустимыми, вы можете передать их в качестве параметров правила валидации:

'url' => 'url:http,https',

'game' => 'url:minecraft,steam',

#ulid

Поле, подлежащее валидации, должно быть корректным Universally Unique Lexicographically Sortable Identifier (ULID).

#uuid

Поле, подлежащее валидации, должно быть допустимым универсальным уникальным идентификатором (UUID) версии 1, 3, 4 или 5 согласно RFC 4122.

#Условное добавление правил

#Пропуск валидации при определённых значениях полей

Иногда может потребоваться не выполнять валидацию определённого поля, если другое поле имеет заданное значение. Это можно сделать с помощью правила валидации exclude_if. В этом примере поля appointment_date и doctor_name не будут валидироваться, если поле has_appointment имеет значение false:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($data, [
    'has_appointment' => 'required|boolean',
    'appointment_date' => 'exclude_if:has_appointment,false|required|date',
    'doctor_name' => 'exclude_if:has_appointment,false|required|string',
]);

Альтернативно, можно использовать правило exclude_unless, чтобы не валидировать поле, если другое поле не имеет заданного значения:

$validator = Validator::make($data, [
    'has_appointment' => 'required|boolean',
    'appointment_date' => 'exclude_unless:has_appointment,true|required|date',
    'doctor_name' => 'exclude_unless:has_appointment,true|required|string',
]);

#Валидация при наличии поля

В некоторых случаях вы можете захотеть выполнять проверку валидации поля только если это поле присутствует в данных для валидации. Для быстрого достижения этого добавьте правило sometimes в список правил:

$v = Validator::make($data, [
    'email' => 'sometimes|required|email',
]);

В приведённом выше примере поле email будет валидироваться только если оно присутствует в массиве $data.

Примечание

Если вы пытаетесь валидировать поле, которое всегда должно присутствовать, но может быть пустым, ознакомьтесь с заметкой об опциональных полях.

#Сложная условная валидация

Иногда требуется добавить правила валидации на основе более сложной условной логики. Например, вы можете захотеть требовать определённое поле только если другое поле имеет значение больше 100. Или вам может понадобиться, чтобы два поля имели заданное значение только при наличии другого поля. Добавлять такие правила несложно. Сначала создайте экземпляр Validator с вашими статическими правилами, которые не меняются:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'email' => 'required|email',
    'games' => 'required|numeric',
]);

Предположим, что наше веб-приложение предназначено для коллекционеров игр. Если коллекционер регистрируется и у него более 100 игр, мы хотим, чтобы он объяснил, почему у него так много игр. Например, возможно, он владеет магазином по перепродаже игр или просто любит коллекционировать. Чтобы условно добавить это требование, мы можем использовать метод sometimes у экземпляра Validator.

use Illuminate\Support\Fluent;

$validator->sometimes('reason', 'required|max:500', function (Fluent $input) {
    return $input->games >= 100;
});

Первый аргумент метода sometimes — имя поля, которое мы условно валидируем. Второй аргумент — список правил, которые нужно добавить. Если замыкание, переданное третьим аргументом, возвращает true, правила будут добавлены. Этот метод значительно упрощает создание сложной условной валидации. Вы даже можете добавить условную валидацию для нескольких полей одновременно:

$validator->sometimes(['reason', 'cost'], 'required', function (Fluent $input) {
    return $input->games >= 100;
});
Примечание

Параметр $input, передаваемый в ваше замыкание, будет экземпляром Illuminate\Support\Fluent и может использоваться для доступа к данным и файлам, подлежащим валидации.

#Сложная условная валидация массивов

Иногда нужно валидировать поле на основе другого поля в том же вложенном массиве, индекс которого неизвестен. В таких случаях вы можете разрешить вашему замыканию принимать второй аргумент — текущий отдельный элемент массива, который валидируется:

$input = [
    'channels' => [
        [
            'type' => 'email',
            'address' => 'abigail@example.com',
        ],
        [
            'type' => 'url',
            'address' => 'https://example.com',
        ],
    ],
];

$validator->sometimes('channels.*.address', 'email', function (Fluent $input, Fluent $item) {
    return $item->type === 'email';
});

$validator->sometimes('channels.*.address', 'url', function (Fluent $input, Fluent $item) {
    return $item->type !== 'email';
});

Как и параметр $input, параметр $item является экземпляром Illuminate\Support\Fluent, когда данные атрибута — массив; в противном случае это строка.

#Валидация массивов

Как обсуждалось в документации к правилу array, правило array принимает список разрешённых ключей массива. Если в массиве присутствуют дополнительные ключи, валидация не пройдёт:

use Illuminate\Support\Facades\Validator;

$input = [
    'user' => [
        'name' => 'Taylor Otwell',
        'username' => 'taylorotwell',
        'admin' => true,
    ],
];

Validator::make($input, [
    'user' => 'array:name,username',
]);

В общем случае всегда следует указывать ключи массива, которые разрешены в вашем массиве. Иначе методы validate и validated валидатора вернут все данные, включая массив и все его ключи, даже если эти ключи не были проверены другими вложенными правилами валидации массива.

#Валидация вложенных массивов

Валидация вложенных массивов в полях формы не должна быть сложной. Вы можете использовать «точечную нотацию» для валидации атрибутов внутри массива. Например, если входящий HTTP-запрос содержит поле photos[profile], вы можете валидировать его так:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'photos.profile' => 'required|image',
]);

Вы также можете валидировать каждый элемент массива. Например, чтобы проверить, что каждый email в массиве уникален, можно сделать следующее:

$validator = Validator::make($request->all(), [
    'person.*.email' => 'email|unique:users',
    'person.*.first_name' => 'required_with:person.*.last_name',
]);

Аналогично, вы можете использовать символ * при указании кастомных сообщений в языковых файлах, что упрощает использование одного сообщения для полей на основе массива:

'custom' => [
    'person.*.email' => [
        'unique' => 'У каждого человека должен быть уникальный адрес электронной почты',
    ]
],

#Доступ к данным вложенных массивов

Иногда нужно получить значение вложенного элемента массива при назначении правил валидации атрибуту. Это можно сделать с помощью метода Rule::forEach. Метод forEach принимает замыкание, которое вызывается для каждого элемента массива, подлежащего валидации, и получает значение элемента и полное имя атрибута. Замыкание должно возвращать массив правил для этого элемента:

use App\Rules\HasPermission;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

$validator = Validator::make($request->all(), [
    'companies.*.id' => Rule::forEach(function (string|null $value, string $attribute) {
        return [
            Rule::exists(Company::class, 'id'),
            new HasPermission('manage-company', $value),
        ];
    }),
]);

#Индексы и позиции в сообщениях об ошибках

При валидации массивов может потребоваться указать индекс или позицию элемента, не прошедшего валидацию, в сообщении об ошибке, отображаемом пользователю. Для этого можно использовать плейсхолдеры :index (начинается с 0) и :position (начинается с 1) в кастомных сообщениях валидации:

use Illuminate\Support\Facades\Validator;

$input = [
    'photos' => [
        [
            'name' => 'BeachVacation.jpg',
            'description' => 'A photo of my beach vacation!',
        ],
        [
            'name' => 'GrandCanyon.jpg',
            'description' => '',
        ],
    ],
];

Validator::validate($input, [
    'photos.*.description' => 'required',
], [
    'photos.*.description.required' => 'Пожалуйста, опишите фото №:position.',
]);

В приведённом примере валидация не пройдёт, и пользователю будет показано сообщение «Пожалуйста, опишите фото №2.»

При необходимости можно ссылаться на более глубоко вложенные индексы и позиции через second-index, second-position, third-index, third-position и так далее.

'photos.*.attributes.*.string' => 'Недопустимый атрибут для фото №:second-position.',

#Валидация файлов

Laravel предоставляет множество правил валидации для загружаемых файлов, таких как mimes, image, min и max. Вы можете указывать эти правила по отдельности при валидации файлов, но Laravel также предлагает удобный fluent-билдер правил для файлов:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\File;

Validator::validate($input, [
    'attachment' => [
        'required',
        File::types(['mp3', 'wav'])
            ->min(1024)
            ->max(12 * 1024),
    ],
]);

Если ваше приложение принимает изображения, загружаемые пользователями, вы можете использовать метод image правила File, чтобы указать, что загружаемый файл должен быть изображением. Кроме того, правило dimensions позволяет ограничить размеры изображения:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File;

Validator::validate($input, [
    'photo' => [
        'required',
        File::image()
            ->min(1024)
            ->max(12 * 1024)
            ->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500)),
    ],
]);
Примечание

Подробнее о валидации размеров изображений можно узнать в документации к правилу dimensions.

#Размеры файлов

Для удобства минимальные и максимальные размеры файлов можно указывать строкой с суффиксом, обозначающим единицы измерения. Поддерживаются суффиксы kb, mb, gb и tb:

File::image()
    ->min('1kb')
    ->max('10mb')

#Типы файлов

Хотя при вызове метода types достаточно указать расширения, этот метод фактически проверяет MIME-тип файла, читая содержимое файла и определяя его MIME-тип. Полный список MIME-типов и соответствующих расширений доступен по адресу:

https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

#Валидация паролей

Чтобы обеспечить достаточный уровень сложности паролей, вы можете использовать объект правила Password в Laravel:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;

$validator = Validator::make($request->all(), [
    'password' => ['required', 'confirmed', Password::min(8)],
]);

Объект правила Password позволяет легко настраивать требования к сложности пароля для вашего приложения, например, указывать, что пароль должен содержать хотя бы одну букву, цифру, символ или символы с разным регистром:

// Требовать минимум 8 символов...
Password::min(8)

// Требовать хотя бы одну букву...
Password::min(8)->letters()

// Требовать хотя бы одну заглавную и одну строчную букву...
Password::min(8)->mixedCase()

// Требовать хотя бы одну цифру...
Password::min(8)->numbers()

// Требовать хотя бы один символ...
Password::min(8)->symbols()

Кроме того, вы можете проверить, не был ли пароль скомпрометирован в результате утечки данных, используя метод uncompromised:

Password::min(8)->uncompromised()

Внутри объект правила Password использует модель k-анонимности для определения, был ли пароль скомпрометирован через сервис haveibeenpwned.com, при этом не нарушая конфиденциальность и безопасность пользователя.

По умолчанию, если пароль встречается хотя бы один раз в утечке данных, он считается скомпрометированным. Вы можете настроить этот порог, передав первый аргумент в метод uncompromised:

// Убедиться, что пароль встречается менее 3 раз в одной утечке данных...
Password::min(8)->uncompromised(3);

Разумеется, вы можете объединять все методы из приведённых выше примеров:

Password::min(8)
    ->letters()
    ->mixedCase()
    ->numbers()
    ->symbols()
    ->uncompromised()

#Определение стандартных правил для паролей

Возможно, вам будет удобно указать стандартные правила валидации паролей в одном месте вашего приложения. Это легко сделать с помощью метода Password::defaults, который принимает замыкание. Замыкание, передаваемое методу defaults, должно возвращать стандартную конфигурацию правила Password. Обычно метод defaults вызывается в методе boot одного из сервис-провайдеров вашего приложения:

use Illuminate\Validation\Rules\Password;

/**
 * Загрузка сервисов приложения.
 */
public function boot(): void
{
    Password::defaults(function () {
        $rule = Password::min(8);

        return $this->app->isProduction()
                    ? $rule->mixedCase()->uncompromised()
                    : $rule;
    });
}

Затем, когда вы захотите применить стандартные правила к конкретному паролю при валидации, вы можете вызвать метод defaults без аргументов:

'password' => ['required', Password::defaults()],

Иногда может потребоваться добавить дополнительные правила валидации к вашим стандартным правилам для паролей. Для этого можно использовать метод rules:

use App\Rules\ZxcvbnRule;

Password::defaults(function () {
    $rule = Password::min(8)->rules([new ZxcvbnRule]);

    // ...
});

#Кастомные правила валидации

#Использование объектов правил

Laravel предоставляет множество полезных правил валидации, однако вы можете захотеть определить свои собственные. Один из способов регистрации кастомных правил — использование объектов правил. Чтобы создать новый объект правила, можно воспользоваться Artisan-командой make:rule. Давайте создадим правило, которое проверяет, что строка написана заглавными буквами. Laravel поместит новое правило в директорию app/Rules. Если этой директории нет, Laravel создаст её при выполнении команды:

php artisan make:rule Uppercase

После создания правила можно определить его поведение. Объект правила содержит один метод: validate. Этот метод получает имя атрибута, его значение и callback, который следует вызвать при ошибке с сообщением об ошибке валидации:

<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class Uppercase implements ValidationRule
{
    /**
     * Run the validation rule.
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (strtoupper($value) !== $value) {
            $fail('The :attribute must be uppercase.');
        }
    }
}

После определения правила вы можете применить его к валидатору, передав экземпляр объекта правила вместе с другими правилами валидации:

use App\Rules\Uppercase;

$request->validate([
    'name' => ['required', 'string', new Uppercase],
]);

Перевод сообщений об ошибках валидации

Вместо передачи буквального сообщения об ошибке в замыкание $fail, вы можете указать ключ строки перевода и поручить Laravel перевести сообщение:

if (strtoupper($value) !== $value) {
    $fail('validation.uppercase')->translate();
}

При необходимости вы можете передать замены плейсхолдеров и предпочитаемый язык в качестве первого и второго аргументов метода translate:

$fail('validation.location')->translate([
    'value' => $this->value,
], 'fr')

Доступ к дополнительным данным

Если вашему классу кастомного правила валидации нужен доступ ко всем остальным данным, проходящим валидацию, класс может реализовать интерфейс Illuminate\Contracts\Validation\DataAwareRule. Этот интерфейс требует определения метода setData, который автоматически вызывается Laravel (до начала валидации) с полным набором данных для валидации:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;

class Uppercase implements DataAwareRule, ValidationRule
{
    /**
     * Все данные, подлежащие валидации.
     *
     * @var array<string, mixed>
     */
    protected $data = [];

    // ...

    /**
     * Установить данные для валидации.
     *
     * @param  array<string, mixed>  $data
     */
    public function setData(array $data): static
    {
        $this->data = $data;

        return $this;
    }
}

Или, если вашему правилу нужен доступ к экземпляру валидатора, выполняющего валидацию, вы можете реализовать интерфейс ValidatorAwareRule:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Validation\Validator;

class Uppercase implements ValidationRule, ValidatorAwareRule
{
    /**
     * Экземпляр валидатора.
     *
     * @var \Illuminate\Validation\Validator
     */
    protected $validator;

    // ...

    /**
     * Установить текущий валидатор.
     */
    public function setValidator(Validator $validator): static
    {
        $this->validator = $validator;

        return $this;
    }
}

Использование замыканий

Если вам нужно использовать кастомное правило только один раз в приложении, можно использовать замыкание вместо объекта правила. Замыкание получает имя атрибута, его значение и callback $fail, который нужно вызвать при ошибке валидации:

use Illuminate\Support\Facades\Validator;
use Closure;

$validator = Validator::make($request->all(), [
    'title' => [
        'required',
        'max:255',
        function (string $attribute, mixed $value, Closure $fail) {
            if ($value === 'foo') {
                $fail("The {$attribute} is invalid.");
            }
        },
    ],
]);

Неявные правила

По умолчанию, если атрибут, подлежащий валидации, отсутствует или содержит пустую строку, обычные правила валидации, включая кастомные, не выполняются. Например, правило unique не будет применяться к пустой строке:

use Illuminate\Support\Facades\Validator;

$rules = ['name' => 'unique:users,name'];

$input = ['name' => ''];

Validator::make($input, $rules)->passes(); // true

Чтобы кастомное правило выполнялось даже при пустом атрибуте, правило должно подразумевать, что атрибут обязателен. Для быстрого создания нового неявного правила можно использовать Artisan-команду make:rule с опцией --implicit:

php artisan make:rule Uppercase --implicit
Внимание

«Неявное» правило лишь подразумевает, что атрибут обязателен. Фактическая проверка отсутствия или пустоты атрибута зависит от вас.