Роутинг, контроллеры, middleware

Маршруты, параметры, Route Model Binding, ресурсные контроллеры, middleware.

Junior Как определяются маршруты в Laravel? Какие HTTP-глаголы поддерживаются?

Маршруты — в routes/web.php (с сессиями, CSRF) и routes/api.php (stateless, префикс /api).

Route::get('/users', [UserController::class, 'index']);
Route::post('/users', [UserController::class, 'store']);
Route::put('/users/{id}', [UserController::class, 'update']);
Route::patch(...); Route::delete(...); Route::options(...);

Route::match(['get', 'post'], '/multi', ...);  // несколько глаголов
Route::any('/all', ...);                        // любой
Route::redirect('/old', '/new', 301);
Route::view('/about', 'pages.about');           // только шаблон
Route::fallback(fn () => ...);                  // если ничего не совпало

Замыкания в роутах — плохая практика для больших приложений: они ломают route:cache и размывают структуру.

Junior Как работают параметры маршрутов? Обязательные, опциональные, ограничения.
Route::get('/users/{id}', fn (int $id) => ...);              // обязательный
Route::get('/users/{name?}', fn (?string $name = null) => ...); // опциональный

// Ограничения регуляркой
Route::get('/users/{id}', ...)->where('id', '[0-9]+');
Route::get('/posts/{slug}', ...)->where('slug', '[a-z0-9-]+');

// Встроенные помощники
Route::get('/users/{id}', ...)->whereNumber('id');
Route::get('/posts/{slug}', ...)->whereAlphaNumeric('slug');

// Глобальный паттерн для {id} — в RouteServiceProvider::boot()
Route::pattern('id', '[0-9]+');

Параметры приходят в контроллер как аргументы метода в порядке следования в URI.

Junior Что такое именованные маршруты и группы маршрутов?

Именованные маршруты позволяют строить URL независимо от URI:

Route::get('/users/{id}', ...)->name('users.show');

route('users.show', ['id' => 5]);      // /users/5
redirect()->route('users.show', 5);

Группы — общие атрибуты для набора маршрутов:

Route::prefix('admin')
    ->name('admin.')
    ->middleware(['auth', 'admin'])
    ->group(function () {
        Route::get('/dashboard', ...)->name('dashboard'); // admin.dashboard
        Route::resource('users', AdminUserController::class);
    });

Атрибуты групп комбинируются: prefix, middleware, name, namespace (legacy), domain, where.

Junior Что даёт Route::resource() и чем отличается от apiResource()?

Route::resource() регистрирует 7 RESTful-маршрутов одним вызовом:

Route::resource('posts', PostController::class);
Метод URI Action Имя
GET /posts index posts.index
GET /posts/create create posts.create
POST /posts store posts.store
GET /posts/{post} show posts.show
GET /posts/{post}/edit edit posts.edit
PUT/PATCH /posts/{post} update posts.update
DELETE /posts/{post} destroy posts.destroy

apiResource() — то же, но без create и edit (формы не нужны в API) — 5 маршрутов.

Ограничение набора:

Route::resource('posts', PostController::class)->only(['index', 'show']);
Route::resource('posts', PostController::class)->except(['destroy']);

Вложенные ресурсы: Route::resource('posts.comments', CommentController::class) → /posts/{post}/comments/{comment}.

Middle Что такое Route Model Binding? Явный и неявный биндинг.

Route Model Binding — автоматическое получение модели по параметру маршрута.

Неявный биндинг: имя параметра совпадает с именем переменной, тип — Eloquent-модель:

Route::get('/users/{user}', function (User $user) {
    return $user; // Laravel сам сделает User::findOrFail($user)
});

Если запись не найдена — автоматически 404.

Ключ поиска по умолчанию — id. Изменить глобально:

public function getRouteKeyName(): string { return 'slug'; }

или точечно: {user:slug}.

Явный биндинг — в провайдере, с кастомной логикой:

Route::bind('user', fn (string $value) =>
    User::where('slug', $value)->where('active', true)->firstOrFail());

Scoped binding {post}/{comment} — дочерняя модель ищется внутри родительской связи.

Middle Что такое middleware? Как создать своё и какие виды существуют?

Middleware — «фильтры» HTTP-запросов: код, выполняемый до/после обработчика. Примеры из коробки: auth, throttle, csrf, cors.

Виды:

  • глобальные — на каждый запрос (регистрируются в bootstrap/app.php);
  • группы — web, api;
  • маршрутные — назначаются на конкретный роут по алиасу;
  • terminable — метод terminate() после отправки ответа (логи, метрики).

Создание:

php artisan make:middleware EnsureUserIsAdmin
public function handle(Request $request, Closure $next): Response
{
    if (! $request->user()?->isAdmin()) {
        abort(403);
    }
    return $next($request);   // до — до $next; после — после
}

Регистрация (Laravel 11+, bootstrap/app.php):

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias(['admin' => EnsureUserIsAdmin::class]);
    $middleware->appendToGroup('web', MyMiddleware::class);
})

Использование: Route::get(...)->middleware('admin'). Параметры: ->middleware('role:editor,admin').

Middle Зачем нужен route:cache и когда его нельзя использовать?
php artisan route:cache   # сериализует все маршруты в bootstrap/cache/routes-*.php
php artisan route:clear

Сотни маршрутов перестают разбираться на каждый запрос → заметное ускорение (особенно с RouteServiceProvider и множеством resource).

Ограничения:

  • нельзя использовать замыкания в маршрутах — их невозможно сериализовать, кэширование упадёт с ошибкой;
  • после изменения роутов кэш нужно пересоздавать (включают в деплой-скрипт);
  • в dev-окружении обычно не используют, чтобы не забывать сбрасывать.

Аналогично: config:cache, view:cache, event:cache — или всё сразу: php artisan optimize.