Урок 04

Именованные роуты

Зачем имя

Без имени:

redirect('/posts/' . $post->id);
<a href="/posts/{{ $post->id }}">Читать</a>

Проблема: если URL изменится с /posts/ на /articles/, нужно править везде.

С именем:

redirect()->route('posts.show', $post);
<a href="{{ route('posts.show', $post) }}">Читать</a>

URL меняется в одном месте — в роуте. Всё остальное работает.

Задание имени

Route::get('/dashboard', function () {
    return view('dashboard');
})->name('dashboard');

->name('dashboard') — имя.

Генерация URL

route('name'):

$url = route('dashboard');   // /dashboard

С параметрами:

Route::get('/posts/{post}', fn ($post) => $post)->name('posts.show');

route('posts.show', ['post' => 5]);   // /posts/5
route('posts.show', 5);                // то же (первый параметр)

Массив — по имени:

route('posts.show', ['post' => 5, 'tab' => 'comments']);
// /posts/5?tab=comments

Лишние параметры → query string.

Редирект по имени

return redirect()->route('posts.index');
return redirect()->route('posts.show', $post);
return to_route('posts.index');   // Laravel 9+

to_route — короткий хелпер.

В Blade

<a href="{{ route('posts.show', $post) }}">Читать</a>
<a href="{{ route('admin.users') }}">Пользователи</a>

<form action="{{ route('posts.store') }}" method="POST">
    @csrf
</form>

Групповые имена

Общий префикс:

Route::name('admin.')->prefix('admin')->group(function () {
    Route::get('/users', fn () => 'Users')->name('users');
    Route::get('/posts', fn () => 'Posts')->name('posts');
});

Имена:

  • admin.users
  • admin.posts

Правило: префикс имени с точкой.

Вложенные:

Route::name('admin.')->group(function () {
    Route::name('users.')->group(function () {
        Route::get('/users', ...)->name('index');   // admin.users.index
    });
});

Имена ресурсов

Route::resource автоматически генерирует:

МетодURLИмя
indexGET /postsposts.index
createGET /posts/createposts.create
storePOST /postsposts.store
showGET /posts/{post}posts.show
editGET /posts/{post}/editposts.edit
updatePUT/PATCH /posts/{post}posts.update
destroyDELETE /posts/{post}posts.destroy

Использование:

route('posts.index');
route('posts.show', $post);
route('posts.edit', $post);

Переопределение имён ресурсов

Route::resource('posts', PostController::class)->names([
    'index' => 'articles.list',
    'show' => 'articles.detail',
]);

Зачем: избежать конфликтов.

Имена и параметры

{post} по умолчанию → имя post.

Переопределить:

Route::resource('posts', PostController::class)
    ->parameters(['posts' => 'article']);

route('posts.show', ['article' => 5]);

Проверка

Route::has('posts.index');   // true / false

В контроллере:

if (Route::has('posts.index')) {
    return redirect()->route('posts.index');
}

Текущий роут

Route::currentRouteName();   // 'posts.show'
Route::is('posts.*');        // текущий из группы
Route::is('posts.show');     // конкретный
Route::is('admin.*');        // группа

В Blade:

<a href="{{ route('posts.index') }}"
   class="{{ request()->routeIs('posts.index') ? 'active' : '' }}">
    Посты
</a>

routeIs — удобнее is.

Имя в middleware

// В middleware
if (!$request->routeIs('admin.*')) {
    // ...
}

Фильтр route:list по имени

php artisan route:list --name=posts
php artisan route:list --name=admin.

Псевдонимы в ресурсе

Альтернативное имя для всего ресурса:

Route::resource('posts', PostController::class)->names('articles');

Имена: articles.index, articles.show, и т.д.

Практика

// routes/web.php

Route::get('/', fn () => view('home'))->name('home');

Route::prefix('blog')->name('blog.')->group(function () {
    Route::get('/', [PostController::class, 'index'])->name('index');
    Route::get('/{post}', [PostController::class, 'show'])->name('show');
});

Route::middleware('auth')->prefix('admin')->name('admin.')->group(function () {
    Route::get('/', [AdminController::class, 'dashboard'])->name('dashboard');
    Route::resource('posts', Admin\PostController::class);
});

Имена:

  • home
  • blog.index
  • blog.show
  • admin.dashboard
  • admin.posts.index, admin.posts.show, ...

Использование:

<a href="{{ route('home') }}">Главная</a>
<a href="{{ route('blog.index') }}">Блог</a>
<a href="{{ route('blog.show', $post) }}">Читать</a>
<a href="{{ route('admin.dashboard') }}">Админка</a>

Частые ошибки

1. Дубликат имени:

Route::get('/a', ...)->name('home');
Route::get('/b', ...)->name('home');   // перезапишет

// Проверка:
php artisan route:list --name=home

2. route() без параметров:

route('posts.show');
// Missing required parameter for [Route: posts.show]

// Правильно:
route('posts.show', $post);

3. Забыли точку в префиксе:

Route::name('admin')->group(...);   // adminposts

// Правильно:
Route::name('admin.')->group(...)

4. Слишком общие имена:

->name('index');   // конфликты

// Правильно:
->name('posts.index');

5. Использование URL вместо имени:

redirect('/posts/' . $post->id);   // сломается при смене URL

// Правильно:
redirect()->route('posts.show', $post);

Итог

  • ->name() — дать имя.
  • route('name', $params) — сгенерировать URL.
  • to_route, redirect()->route — редиректы.
  • Route::has('name') — проверка.
  • Route::is, request()->routeIs() — текущий.
  • admin. — групповой префикс.
  • Ресурсы — авто-имена.
  • Правило: никогда не хардкодь URL.

Дальше — группы роутов.