Тема
Controllers, Routing, Middleware, Validation
Роль контроллера
Контроллер — тонкая прослойка. Три действия:
- Принять и провалидировать input (FormRequest)
- Вызвать сервис
- Вернуть response (view / json / redirect)
Если в методе контроллера больше 10 строк логики — она должна быть в Service.
Routing
Route Model Binding
- По
slug— для публичных сущностей ({category:slug},{product:slug}) - По
id— только для внутренних/admin сущностей - Вложенные модели с
scopeBindings()— Laravel автоматически проверяет принадлежность child к parent
Группировка
- По
prefix— общий URL-префикс (/catalog/*,/api/*) - По
middleware— общие middleware (throttle,auth) - По
name— общий prefix для имён роутов (catalog.index,catalog.show)
Именование
Каждый роут ДОЛЖЕН иметь имя через ->name(). Ссылки в коде — только через route('name'), никогда хардкод URL.
Редиректы
- 301 — permanent (для SEO, при переименовании URL)
- 302 — temporary (для временных перенаправлений)
- При любом изменении URL — обязателен 301 со старого адреса
Fallback
Определять fallback-роут для 404 — чтобы кастомная страница, а не дефолтная Laravel.
FormRequest (Validation)
- Отдельный FormRequest-класс для каждой формы/endpoint
- Валидация НИКОГДА не в контроллере — только в FormRequest
authorize()— true для публичных форм, проверка прав для защищённыхmessages()— кастомные сообщения на русском для пользовательских форм
Правила валидации
requiredvsnullable— осознанный выбор, не "на всякий случай"max:255на все string поля — защита от переполненияemail:rfc,dns— проверяет формат И существование доменаexists:table,column— для FK, проверка что связанная запись существуетunique:table,columnсignoreRecordпри update- Regex для телефонов и специфичных форматов
- Кастомные правила через
Rule::или invokable rule class
Middleware
Регистрация
Laravel 11+: в bootstrap/app.php через ->withMiddleware(), не в Kernel.php.
Типичные middleware
| Middleware | Назначение | Где применять |
|---|---|---|
throttle:X,Y | Rate limiting | API POST endpoints |
| Кастомный PageCache | Кеш GET-страниц в Redis | Публичные GET-роуты |
| Кастомный ResolveCity | Определение текущего города | Все публичные роуты |
auth | Авторизация | Admin-роуты |
verified | Подтверждение email | Защищённые действия |
Правила
- Middleware применять к группе роутов, не к каждому отдельно
- Middleware НЕ содержит бизнес-логику — только фильтрация/подготовка request
- Тяжёлые операции (DB-запросы) в middleware — минимизировать, кешировать
API Controllers
Коды ответов
| Код | Когда |
|---|---|
| 200 | GET успешный |
| 201 | POST создал ресурс |
| 204 | DELETE успешный, нет тела |
| 422 | Ошибка валидации (Laravel default) |
| 429 | Rate limit exceeded |
| 404 | Ресурс не найден |
| 500 | Серверная ошибка — НЕ возвращать детали в production |
Правила
- Возвращать JSON, не HTML
- Для сложных ответов — API Resources (трансформация модели в JSON)
- Rate limiting (
throttle) на каждый POST/PUT/DELETE endpoint - Не раскрывать внутренние ошибки (stack traces) в production
Anti-patterns
| Паттерн | Проблема | Решение |
|---|---|---|
$request->validate() в контроллере | Валидация не в том месте | FormRequest |
| Больше 10 строк логики в методе контроллера | Fat controller | Service |
dd() / dump() в контроллере | Остаётся в коде | Логгер, Telescope |
Прямой DB:: в контроллере | Обход слоёв | Через модель/сервис |
| Хардкод URL в redirect | Ломается при смене роутов | route('name') |
Роут без ->name() | Невозможно ссылаться | Всегда именовать |
| Middleware с бизнес-логикой | Не то место | Логику в Service |
| Один контроллер на 20+ роутов | God controller | Разбить по доменам |