Классы запросов
Когда у формы десять полей, правила проверки занимают половину метода контроллера. Класс запроса — Form Request — забирает их к себе. Контроллер получает уже проверенные данные и занимается только своим делом.
Создание
php artisan make:request StorePostRequestКласс появится в app/Http/Requests.
Правила
Правила возвращает метод rules(). Их удобно записывать массивами:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'body' => ['required', 'string'],
'category_id' => ['required', 'exists:categories,id'],
'tags' => ['array'],
'tags.*' => ['integer', 'exists:tags,id'],
];
}
}Правило exists проверяет, что такая запись есть в таблице. Запись tags.* задаёт правила для каждого элемента массива.
Использование в контроллере
Достаточно указать класс в типе параметра. Проверка выполнится до входа в метод:
public function store(StorePostRequest $request)
{
$post = Post::create($request->validated());
return redirect()->route('posts.show', $post);
}validated() возвращает только те поля, для которых заданы правила. Лишние данные из запроса в базу не попадут.
Проверка прав
Метод authorize() решает, можно ли вообще выполнять запрос. Если он вернёт false, пользователь получит ошибку 403:
public function authorize(): bool
{
return $this->user()->can('update', $this->route('post'));
}Свои сообщения
public function messages(): array
{
return [
'title.required' => 'Укажите заголовок статьи.',
'title.max' => 'Заголовок не длиннее 255 символов.',
];
}
public function attributes(): array
{
return [
'category_id' => 'категория',
];
}attributes() заменяет в стандартных сообщениях имя поля на понятное название.
Подготовка данных
prepareForValidation() выполняется до проверки — в нём приводят данные к нужному виду:
use Illuminate\Support\Str;
protected function prepareForValidation(): void
{
$this->merge([
'slug' => Str::slug($this->title),
'is_published' => $this->boolean('is_published'),
]);
}Правила, зависящие от записи
При редактировании уникальность нужно проверять, исключая саму запись:
use Illuminate\Validation\Rule;
public function rules(): array
{
return [
'slug' => ['required', Rule::unique('posts')->ignore($this->route('post'))],
'status' => ['required', Rule::in(['draft', 'published'])],
];
}Частая ошибка
Метод $request->all() возвращает всё, что прислал пользователь, включая поля, которых нет в правилах. Передав его в create(), вы позволите подставить лишнее поле — например, is_admin. Берите данные только из validated().