Урок 05

Группы роутов

Зачем группы

Без группы:

Route::get('/admin/users', ...)->middleware('auth');
Route::get('/admin/posts', ...)->middleware('auth');
Route::get('/admin/settings', ...)->middleware('auth');

С группой:

Route::middleware('auth')->prefix('admin')->name('admin.')->group(function () {
    Route::get('/users', ...);
    Route::get('/posts', ...);
    Route::get('/settings', ...);
});

Меньше дублирования.

Префикс

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

Что даёт: URL получают общий префикс.

Вложенные:

Route::prefix('api')->group(function () {
    Route::prefix('v1')->group(function () {
        Route::get('/users', ...);   // /api/v1/users
    });
});

Middleware

Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('/dashboard', fn () => 'Dashboard');
    Route::get('/profile', fn () => 'Profile');
});

Каждый роут в группе получает middleware.

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

Route::middleware(['auth', 'role:admin'])->group(...);

Имена

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

⚠️ Точка в конце — обязательна для конкатенации.

Комбинация

Всё вместе:

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

Что даёт:

  • URL: /admin/users, /admin/posts.
  • Имена: admin.users, admin.posts.
  • Middleware: auth.

Домен

Привязка к домену:

Route::domain('admin.example.com')->group(function () {
    Route::get('/users', fn () => 'Users');
});

Открыть: http://admin.example.com/users.

Динамический поддомен

Route::domain('{account}.example.com')->group(function () {
    Route::get('/dashboard', function ($account) {
        return "Account: {$account}";
    });
});

{account} — параметр из поддомена.

Пример: http://ivan.example.com/dashboard → $account = 'ivan'.

Вложенные группы

Route::prefix('api')->group(function () {
    Route::name('api.')->group(function () {
        Route::middleware('auth:sanctum')->group(function () {
            Route::get('/users', ...);   // /api/users, api.users, auth:sanctum
        });
    });
});

// Или короче:
Route::prefix('api')->name('api.')->middleware('auth:sanctum')->group(function () {
    Route::get('/users', ...);
});

Массивное задание атрибутов

Через массив:

Route::group([
    'prefix' => 'admin',
    'middleware' => ['auth', 'admin'],
    'as' => 'admin.',
], function () {
    Route::get('/users', ...);
});

Старый синтаксис, но работает.

Route::controller

Группировка по контроллеру:

use App\Http\Controllers\PostController;

Route::controller(PostController::class)->group(function () {
    Route::get('/posts', 'index');
    Route::get('/posts/{id}', 'show');
    Route::post('/posts', 'store');
});

Что даёт: не повторяешь [PostController::class, ...].

Route::resources — несколько

Route::resources([
    'posts' => PostController::class,
    'comments' => CommentController::class,
    'tags' => TagController::class,
]);

Короче, чем три resource.

Файлы роутов

Для больших проектов — вынести в отдельные файлы.

bootstrap/app.php:

->withRouting(
    web: __DIR__.'/../routes/web.php',
    api: __DIR__.'/../routes/api.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
    then: function () {
        Route::middleware('web')
            ->prefix('admin')
            ->name('admin.')
            ->group(base_path('routes/admin.php'));

        Route::middleware('web')
            ->prefix('account')
            ->name('account.')
            ->group(base_path('routes/account.php'));
    },
)

routes/admin.php:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
Route::resource('users', UserController::class);
Route::resource('posts', PostController::class);

Плюс: чистые файлы.

Просмотр

php artisan route:list --path=admin
php artisan route:list --name=admin.
php artisan route:list --middleware=auth
php artisan route:list --domain=admin.example.com

Практика: админка

// routes/web.php

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

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

        Route::resource('users', Admin\UserController::class);
        Route::resource('posts', Admin\PostController::class);

        Route::middleware('admin')->group(function () {
            Route::get('/settings', [SettingsController::class, 'index'])->name('settings');
        });
    });

Что получилось:

  • /admin → admin.dashboard.
  • /admin/users → admin.users.index.
  • /admin/posts → admin.posts.index.
  • /admin/settings → только для админов.

Всё требует auth.

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

1. Забыли точку в name:

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

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

2. group не в конце цепочки:

Route::group(function () { })->middleware('auth');   // не сработает

// Правильно:
Route::middleware('auth')->group(function () { })

3. Слишком глубокая вложенность:

Route::group(function () {
    Route::group(function () {
        Route::group(function () {
            // 3+ уровня — плохо
        });
    });
});

Решение: максимум 2 уровня.

4. Повторение middleware:

Route::middleware('auth')->group(function () {
    Route::get('/a', ...)->middleware('auth');   // дублирование
});

5. Конфликт имён:

Route::name('admin.')->group(function () {
    Route::get('/a', ...)->name('users');
});
Route::name('admin.')->group(function () {
    Route::get('/b', ...)->name('users');   // дубликат
});

Итог

  • prefix — URL-префикс.
  • middleware — общая обёртка.
  • name('prefix.') — префикс имени.
  • domain — поддомен.
  • controller — группировка по контроллеру.
  • Вложенные группы — максимум 2 уровня.
  • Файлы — для больших проектов.
  • Правило: общее — в группу.

Дальше — контроллеры: основы.