Группы роутов
Зачем группы
Без группы:
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 уровня.
- Файлы — для больших проектов.
- Правило: общее — в группу.
Дальше — контроллеры: основы.