HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Существуют<strong>проекты на Laravel</strong>с сотнями маршрутов и отдельными секциями для пользователей, гостей и администраторов. Хранить всё это в одном файле неразумно и неэффективно. Возникает вопрос, как маршруты сгруппировать и добавить префиксы в URL? В этой статье мы посмотрим, что можно сделать.</p>
1 <p>Существуют<strong>проекты на Laravel</strong>с сотнями маршрутов и отдельными секциями для пользователей, гостей и администраторов. Хранить всё это в одном файле неразумно и неэффективно. Возникает вопрос, как маршруты сгруппировать и добавить префиксы в URL? В этой статье мы посмотрим, что можно сделать.</p>
2 <h2>1. Разделяем WEB- и API-маршруты</h2>
2 <h2>1. Разделяем WEB- и API-маршруты</h2>
3 <p>Это совсем просто, ведь Laravel выполняет данную операцию по умолчанию. Можно создать 2 файла: - routes/web.php; - routes/api.php.</p>
3 <p>Это совсем просто, ведь Laravel выполняет данную операцию по умолчанию. Можно создать 2 файла: - routes/web.php; - routes/api.php.</p>
4 <p>Если проект имеет и API-страницы и веб-страницы, поместите API-маршруты в отдельный файл. Представьте, что есть страница<strong>/users</strong>, а также конечная точка<strong>/api/users/</strong>. Если их разделить на отдельные файлы, вы не запутаетесь в одинаковых именах.</p>
4 <p>Если проект имеет и API-страницы и веб-страницы, поместите API-маршруты в отдельный файл. Представьте, что есть страница<strong>/users</strong>, а также конечная точка<strong>/api/users/</strong>. Если их разделить на отдельные файлы, вы не запутаетесь в одинаковых именах.</p>
5 <p>Однако структурирование делается по индивидуальным предпочтениям, 100%-го стандарта не существует. Доказательство этому - нелогичный пример в официальном Laravel-проекте Horizon у Тейлора. Проект имеет API-маршруты, но отдельный файл не используется - проекта помещён в route/web.php:</p>
5 <p>Однако структурирование делается по индивидуальным предпочтениям, 100%-го стандарта не существует. Доказательство этому - нелогичный пример в официальном Laravel-проекте Horizon у Тейлора. Проект имеет API-маршруты, но отдельный файл не используется - проекта помещён в route/web.php:</p>
6 <h2>2. Структурируем файл routs/web.php в Группы</h2>
6 <h2>2. Структурируем файл routs/web.php в Группы</h2>
7 <p>Группировка маршрутов тоже возможна в "базовом" Laravel. Вот пример из<a>официальной документации</a>:</p>
7 <p>Группировка маршрутов тоже возможна в "базовом" Laravel. Вот пример из<a>официальной документации</a>:</p>
8 Route::middleware(['first', 'second'])-&gt;group(function () { Route::get('/', function () { // использует мидлвары first и second }); Route::get('user/profile', function () { // использует мидлвары first и second }); });<p>Особенности применения - скрытие разных групп под различными мидлварами. К примеру, одну группу можно ограничить дефолтным auth-мидлваром, а другую - отдельным администраторским и т. п.</p>
8 Route::middleware(['first', 'second'])-&gt;group(function () { Route::get('/', function () { // использует мидлвары first и second }); Route::get('user/profile', function () { // использует мидлвары first и second }); });<p>Особенности применения - скрытие разных групп под различными мидлварами. К примеру, одну группу можно ограничить дефолтным auth-мидлваром, а другую - отдельным администраторским и т. п.</p>
9 <p>И можно использовать как имена, так и префиксы групп маршрутов. Вот ещё парочка примеров из официальной документации:</p>
9 <p>И можно использовать как имена, так и префиксы групп маршрутов. Вот ещё парочка примеров из официальной документации:</p>
10 Route::prefix('admin')-&gt;group(function () { Route::get('users', function () { // Соответствует адресу "/admin/users" }); }); Route::name('admin.')-&gt;group(function () { Route::get('users', function () { // Маршруту присваивается имя "admin.users"... })-&gt;name('users'); });<p>Желаете добавить мидлвар+имя+префикс в одну группу?<strong>Сделайте их массивом</strong>, тогда их будет удобнее читать:</p>
10 Route::prefix('admin')-&gt;group(function () { Route::get('users', function () { // Соответствует адресу "/admin/users" }); }); Route::name('admin.')-&gt;group(function () { Route::get('users', function () { // Маршруту присваивается имя "admin.users"... })-&gt;name('users'); });<p>Желаете добавить мидлвар+имя+префикс в одну группу?<strong>Сделайте их массивом</strong>, тогда их будет удобнее читать:</p>
11 // Вместо такой цепочки Route::name('admin.')-&gt;prefix('admin')-&gt;middleware('admin')-&gt;group(function () { // ... }); // Можно использовать массив Route::group([ 'name' =&gt; 'admin.', 'prefix' =&gt; 'admin', 'middleware' =&gt; 'auth' ], function () { // ... });<p>А теперь соединим всё в реальном примере: - Группа "Гость" без мидлвара и с адресами /front/XXXXX; - Группа "Пользователь" с auth-мидлваром и адресами /user/XXXXX; - Группа "Администратор" с отдельным admin-мидлваром и адресами /admin/XXXXX.</p>
11 // Вместо такой цепочки Route::name('admin.')-&gt;prefix('admin')-&gt;middleware('admin')-&gt;group(function () { // ... }); // Можно использовать массив Route::group([ 'name' =&gt; 'admin.', 'prefix' =&gt; 'admin', 'middleware' =&gt; 'auth' ], function () { // ... });<p>А теперь соединим всё в реальном примере: - Группа "Гость" без мидлвара и с адресами /front/XXXXX; - Группа "Пользователь" с auth-мидлваром и адресами /user/XXXXX; - Группа "Администратор" с отдельным admin-мидлваром и адресами /admin/XXXXX.</p>
12 <p>Выполняем группировку всего этого в файле routs/web.php:</p>
12 <p>Выполняем группировку всего этого в файле routs/web.php:</p>
13 Route::group([ 'name' =&gt; 'admin.', 'prefix' =&gt; 'admin', 'middleware' =&gt; 'admin' ], function () { // адрес: /admin/users // имя маршрута: admin.users Route::get('users', function () { return 'Admin: user list'; })-&gt;name('users'); }); Route::group([ 'name' =&gt; 'user.', 'prefix' =&gt; 'user', 'middleware' =&gt; 'auth' ], function () { // адрес: /user/profile // имя маршрута: user.profile Route::get('profile', function () { return 'User profile'; })-&gt;name('profile'); }); Route::group([ 'name' =&gt; 'front.', 'prefix' =&gt; 'front' ], function () { // без мидлвара // адрес: /front/about-us // имя маршрута: front.about Route::get('about-us', function () { return 'About us page'; })-&gt;name('about'); });<h2>3. Группируем контроллеры с пространствами имён</h2>
13 Route::group([ 'name' =&gt; 'admin.', 'prefix' =&gt; 'admin', 'middleware' =&gt; 'admin' ], function () { // адрес: /admin/users // имя маршрута: admin.users Route::get('users', function () { return 'Admin: user list'; })-&gt;name('users'); }); Route::group([ 'name' =&gt; 'user.', 'prefix' =&gt; 'user', 'middleware' =&gt; 'auth' ], function () { // адрес: /user/profile // имя маршрута: user.profile Route::get('profile', function () { return 'User profile'; })-&gt;name('profile'); }); Route::group([ 'name' =&gt; 'front.', 'prefix' =&gt; 'front' ], function () { // без мидлвара // адрес: /front/about-us // имя маршрута: front.about Route::get('about-us', function () { return 'About us page'; })-&gt;name('about'); });<h2>3. Группируем контроллеры с пространствами имён</h2>
14 <p>В примере выше мы не использовали контроллеры, а возвращали статический текст. Можно добавить контроллеры с ещё одним "поворотом" - в результате получим структуризацию по папкам с их собственными пространствами имен:</p>
14 <p>В примере выше мы не использовали контроллеры, а возвращали статический текст. Можно добавить контроллеры с ещё одним "поворотом" - в результате получим структуризацию по папкам с их собственными пространствами имен:</p>
15 <p>И сможем применить их в файле маршрутов:</p>
15 <p>И сможем применить их в файле маршрутов:</p>
16 Route::group([ 'name' =&gt; 'front.', 'prefix' =&gt; 'front' ], function () { Route::get('about-us', 'Front\AboutController@index')-&gt;name('about'); });<p>Но что произойдёт, если в данной группе будет много контроллеров? Потребуется ли постоянно добавлять Front\SomeController? Разумеется, нет. Вы просто указываете пространство имен в виде одного из параметров.</p>
16 Route::group([ 'name' =&gt; 'front.', 'prefix' =&gt; 'front' ], function () { Route::get('about-us', 'Front\AboutController@index')-&gt;name('about'); });<p>Но что произойдёт, если в данной группе будет много контроллеров? Потребуется ли постоянно добавлять Front\SomeController? Разумеется, нет. Вы просто указываете пространство имен в виде одного из параметров.</p>
17 Route::group([ 'name' =&gt; 'front.', 'prefix' =&gt; 'front', 'namespace' =&gt; 'Front', ], function () { Route::get('about-us', 'AboutController@index')-&gt;name('about'); Route::get('contact', 'ContactController@index')-&gt;name('contact'); });<h2>4. Группа в группе</h2>
17 Route::group([ 'name' =&gt; 'front.', 'prefix' =&gt; 'front', 'namespace' =&gt; 'Front', ], function () { Route::get('about-us', 'AboutController@index')-&gt;name('about'); Route::get('contact', 'ContactController@index')-&gt;name('contact'); });<h2>4. Группа в группе</h2>
18 <p>Указанная выше ситуация с 3-мя группами упрощена. В действительности реальные проекты отличаются немного другой структурой, включающей в себя 2 группы: front и auth. И внутри auth существуют подгруппы: user и admin . Можно создать подгруппы в routes/web.php, а потом назначить разные мидлвары/префиксы и т. п.</p>
18 <p>Указанная выше ситуация с 3-мя группами упрощена. В действительности реальные проекты отличаются немного другой структурой, включающей в себя 2 группы: front и auth. И внутри auth существуют подгруппы: user и admin . Можно создать подгруппы в routes/web.php, а потом назначить разные мидлвары/префиксы и т. п.</p>
19 Route::group([ 'middleware' =&gt; 'auth', ], function() { Route::group([ 'name' =&gt; 'admin.', 'prefix' =&gt; 'admin', 'middleware' =&gt; 'admin' ], function () { // адрес: /admin/users // имя маршрута: admin.users Route::get('users', 'UserController@index')-&gt;name('users'); }); Route::group([ 'name' =&gt; 'user.', 'prefix' =&gt; 'user', ], function () { // адрес: /user/profile // имя маршрута: user.profile Route::get('profile', 'ProfileController@index')-&gt;name('profile'); }); });<p>Мало того, можно сделать более, чем 2 уровня, как в примере из открытого проекта<a>Akaunting</a>:</p>
19 Route::group([ 'middleware' =&gt; 'auth', ], function() { Route::group([ 'name' =&gt; 'admin.', 'prefix' =&gt; 'admin', 'middleware' =&gt; 'admin' ], function () { // адрес: /admin/users // имя маршрута: admin.users Route::get('users', 'UserController@index')-&gt;name('users'); }); Route::group([ 'name' =&gt; 'user.', 'prefix' =&gt; 'user', ], function () { // адрес: /user/profile // имя маршрута: user.profile Route::get('profile', 'ProfileController@index')-&gt;name('profile'); }); });<p>Мало того, можно сделать более, чем 2 уровня, как в примере из открытого проекта<a>Akaunting</a>:</p>
20 Route::group(['middleware' =&gt; 'language'], function () { Route::group(['middleware' =&gt; 'auth'], function () { Route::group(['prefix' =&gt; 'uploads'], function () { Route::get('{id}', 'Common\Uploads@get'); Route::get('{id}/show', 'Common\Uploads@show'); Route::get('{id}/download', 'Common\Uploads@download'); }); Route::group(['middleware' =&gt; 'permission:read-admin-panel'], function () { Route::group(['prefix' =&gt; 'wizard'], function () { Route::get('/', 'Wizard\Companies@edit')-&gt;name('wizard.index'); // ...<p>Или из проекта<a>Monica</a>:</p>
20 Route::group(['middleware' =&gt; 'language'], function () { Route::group(['middleware' =&gt; 'auth'], function () { Route::group(['prefix' =&gt; 'uploads'], function () { Route::get('{id}', 'Common\Uploads@get'); Route::get('{id}/show', 'Common\Uploads@show'); Route::get('{id}/download', 'Common\Uploads@download'); }); Route::group(['middleware' =&gt; 'permission:read-admin-panel'], function () { Route::group(['prefix' =&gt; 'wizard'], function () { Route::get('/', 'Wizard\Companies@edit')-&gt;name('wizard.index'); // ...<p>Или из проекта<a>Monica</a>:</p>
21 Route::middleware(['auth', 'verified', 'mfa'])-&gt;group(function () { Route::name('dashboard.')-&gt;group(function () { Route::get('/dashboard', 'DashboardController@index')-&gt;name('index'); Route::get('/dashboard/calls', 'DashboardController@calls'); Route::get('/dashboard/notes', 'DashboardController@notes'); Route::get('/dashboard/debts', 'DashboardController@debts'); Route::get('/dashboard/tasks', 'DashboardController@tasks'); Route::post('/dashboard/setTab', 'DashboardController@setTab'); });<h2>5. Глобальные настройки в RouteServiceProvider</h2>
21 Route::middleware(['auth', 'verified', 'mfa'])-&gt;group(function () { Route::name('dashboard.')-&gt;group(function () { Route::get('/dashboard', 'DashboardController@index')-&gt;name('index'); Route::get('/dashboard/calls', 'DashboardController@calls'); Route::get('/dashboard/notes', 'DashboardController@notes'); Route::get('/dashboard/debts', 'DashboardController@debts'); Route::get('/dashboard/tasks', 'DashboardController@tasks'); Route::post('/dashboard/setTab', 'DashboardController@setTab'); });<h2>5. Глобальные настройки в RouteServiceProvider</h2>
22 <p>Существует файл, настраивающий все маршруты - это app/Providers/RouteServiceProvider.php. В нём есть метод map(), благодаря которому оба файла маршрутов - web и API связываются:</p>
22 <p>Существует файл, настраивающий все маршруты - это app/Providers/RouteServiceProvider.php. В нём есть метод map(), благодаря которому оба файла маршрутов - web и API связываются:</p>
23 public function map() { $this-&gt;mapApiRoutes(); $this-&gt;mapWebRoutes(); } protected function mapWebRoutes() { Route::middleware('web') -&gt;namespace($this-&gt;namespace) -&gt;group(base_path('routes/web.php')); } protected function mapApiRoutes() { Route::prefix('api') -&gt;middleware('api') -&gt;namespace($this-&gt;namespace) -&gt;group(base_path('routes/api.php')); }<p>Заметили ли вы, что в методах упоминается пространство имен, мидлвар и префикс? И здесь можно устанавливать глобальные настройки для маршрутов, тогда вам не придётся повторять их для каждой группы.</p>
23 public function map() { $this-&gt;mapApiRoutes(); $this-&gt;mapWebRoutes(); } protected function mapWebRoutes() { Route::middleware('web') -&gt;namespace($this-&gt;namespace) -&gt;group(base_path('routes/web.php')); } protected function mapApiRoutes() { Route::prefix('api') -&gt;middleware('api') -&gt;namespace($this-&gt;namespace) -&gt;group(base_path('routes/api.php')); }<p>Заметили ли вы, что в методах упоминается пространство имен, мидлвар и префикс? И здесь можно устанавливать глобальные настройки для маршрутов, тогда вам не придётся повторять их для каждой группы.</p>
24 <p>Как правило, данный файл используется для API-маршрутов, ведь их настройки обычно одинаковы:</p>
24 <p>Как правило, данный файл используется для API-маршрутов, ведь их настройки обычно одинаковы:</p>
25 protected function mapApiRoutes() { Route::group([ 'middleware' =&gt; ['api'], 'namespace' =&gt; $this-&gt;namespace, 'prefix' =&gt; 'api/v1', ], function ($router) { require base_path('routes/api.php'); }); }<p>А с помощью метода выше вы добавите префикс "api/v1/" для всех адресов API.</p>
25 protected function mapApiRoutes() { Route::group([ 'middleware' =&gt; ['api'], 'namespace' =&gt; $this-&gt;namespace, 'prefix' =&gt; 'api/v1', ], function ($router) { require base_path('routes/api.php'); }); }<p>А с помощью метода выше вы добавите префикс "api/v1/" для всех адресов API.</p>
26 <h2>6. Группировка по файлам - стоит ли овчинка выделки?</h2>
26 <h2>6. Группировка по файлам - стоит ли овчинка выделки?</h2>
27 <p>Если у вас большое число маршрутов, и вы желаете ещё больше сгруппировать их в отдельные файлы, можно задействовать файл, упоминавшийся в предыдущем пункте -<strong>app/Providers/RouteServiceProvider.php</strong>.</p>
27 <p>Если у вас большое число маршрутов, и вы желаете ещё больше сгруппировать их в отдельные файлы, можно задействовать файл, упоминавшийся в предыдущем пункте -<strong>app/Providers/RouteServiceProvider.php</strong>.</p>
28 <p>Присмотревшись к методу map(), вы увидите в конце закомментированное место:</p>
28 <p>Присмотревшись к методу map(), вы увидите в конце закомментированное место:</p>
29 public function map() { $this-&gt;mapApiRoutes(); $this-&gt;mapWebRoutes(); // }<p>Можно интерпретировать это, как в некотором роде "приглашение" и добавить ещё файлы, если пожелаете. Так вы сможете создать внутри файла ещё один метод, к примеру, mapAdminRoutes()с последующим добавлением его в метод map(). В итоге файл будет и зарегистрирован, и автоматически загружен.</p>
29 public function map() { $this-&gt;mapApiRoutes(); $this-&gt;mapWebRoutes(); // }<p>Можно интерпретировать это, как в некотором роде "приглашение" и добавить ещё файлы, если пожелаете. Так вы сможете создать внутри файла ещё один метод, к примеру, mapAdminRoutes()с последующим добавлением его в метод map(). В итоге файл будет и зарегистрирован, и автоматически загружен.</p>
30 <p>С одной стороны, это даёт чуть большее разделение маршрутов, с другой - вы иногда теряетесь в этих файлах и пытаетесь вспомнить, где искать конкретный маршрут.</p>
30 <p>С одной стороны, это даёт чуть большее разделение маршрутов, с другой - вы иногда теряетесь в этих файлах и пытаетесь вспомнить, где искать конкретный маршрут.</p>
31 <h2>7. Находим точный маршрут с помощью Artisan route:list</h2>
31 <h2>7. Находим точный маршрут с помощью Artisan route:list</h2>
32 <p>В некоторых случаях нужный маршрут поможет найти<strong>artisan-команда</strong>. Скорее всего, вы в курсе, что<strong>php artisan route:list</strong>позволяет показать все маршруты в проекте:</p>
32 <p>В некоторых случаях нужный маршрут поможет найти<strong>artisan-команда</strong>. Скорее всего, вы в курсе, что<strong>php artisan route:list</strong>позволяет показать все маршруты в проекте:</p>
33 <p>Но в курсе ли вы, что есть возможность фильтрации вывода с целью нахождения именно того, что надо? Для этого добавьте -method, либо -name, либо -path с параметрами.</p>
33 <p>Но в курсе ли вы, что есть возможность фильтрации вывода с целью нахождения именно того, что надо? Для этого добавьте -method, либо -name, либо -path с параметрами.</p>
34 <p>Смотрим фильтрование по методу POST, GET, и т. д.</p>
34 <p>Смотрим фильтрование по методу POST, GET, и т. д.</p>
35 <p>А вот фильтрование по части адреса или имени:</p>
35 <p>А вот фильтрование по части адреса или имени:</p>
36 <p>Пожалуй, это всё, что можно рассказать о группировке маршрутов в крупных Laravel-проектах.</p>
36 <p>Пожалуй, это всё, что можно рассказать о группировке маршрутов в крупных Laravel-проектах.</p>
37  
37