Курсы

Курсы в разработке Подготовительные курсы
Работа в компаниях Компаниям Блог +7 499 110-61-65

Структурируем маршруты в крупных проектах на Laravel

Laravel_Deep_23.7_site-5020-86729a.png

Существуют проекты на Laravel с сотнями маршрутов и отдельными секциями для пользователей, гостей и администраторов. Хранить всё это в одном файле неразумно и неэффективно. Возникает вопрос, как маршруты сгруппировать и добавить префиксы в URL? В этой статье мы посмотрим, что можно сделать.

1. Разделяем WEB- и API-маршруты

Это совсем просто, ведь Laravel выполняет данную операцию по умолчанию. Можно создать 2 файла: — routes/web.php; — routes/api.php.

Если проект имеет и API-страницы и веб-страницы, поместите API-маршруты в отдельный файл. Представьте, что есть страница /users, а также конечная точка /api/users/. Если их разделить на отдельные файлы, вы не запутаетесь в одинаковых именах.

Однако структурирование делается по индивидуальным предпочтениям, 100%-го стандарта не существует. Доказательство этому — нелогичный пример в официальном Laravel-проекте Horizon у Тейлора. Проект имеет API-маршруты, но отдельный файл не используется — проекта помещён в route/web.php:

1-20219-ce473f.png

2. Структурируем файл routs/web.php в Группы

Группировка маршрутов тоже возможна в «базовом» Laravel. Вот пример из официальной документации:

Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// использует мидлвары first и second
});

Route::get('user/profile', function () {
// использует мидлвары first и second
});
});

Особенности применения — скрытие разных групп под различными мидлварами. К примеру, одну группу можно ограничить дефолтным auth-мидлваром, а другую — отдельным администраторским и т. п.

И можно использовать как имена, так и префиксы групп маршрутов. Вот ещё парочка примеров из официальной документации:

Route::prefix('admin')->group(function () {
Route::get('users', function () {
// Соответствует адресу "/admin/users"
});
});

Route::name('admin.')->group(function () {
Route::get('users', function () {
// Маршруту присваивается имя "admin.users"...
})->name('users');
});

Желаете добавить мидлвар+имя+префикс в одну группу? Сделайте их массивом, тогда их будет удобнее читать:

// Вместо такой цепочки
Route::name('admin.')->prefix('admin')->middleware('admin')->group(function () {
// ...
});

// Можно использовать массив
Route::group([
'name' => 'admin.', 
'prefix' => 'admin', 
'middleware' => 'auth'
], function () {
// ...
});

А теперь соединим всё в реальном примере: — Группа «Гость» без мидлвара и с адресами /front/XXXXX; — Группа «Пользователь» с auth-мидлваром и адресами /user/XXXXX; — Группа «Администратор» с отдельным admin-мидлваром и адресами /admin/XXXXX.

Выполняем группировку всего этого в файле routs/web.php:

Route::group([
'name' => 'admin.',
'prefix' => 'admin',
'middleware' => 'admin'
], function () {

// адрес: /admin/users
// имя маршрута: admin.users
Route::get('users', function () {
return 'Admin: user list';
})->name('users');

});

Route::group([
'name' => 'user.',
'prefix' => 'user',
'middleware' => 'auth'
], function () {

// адрес: /user/profile
// имя маршрута: user.profile
Route::get('profile', function () {
return 'User profile';
})->name('profile');

});

Route::group([
'name' => 'front.',
'prefix' => 'front'
], function () {

// без мидлвара
// адрес: /front/about-us
// имя маршрута: front.about
Route::get('about-us', function () {
return 'About us page';
})->name('about');

});

3. Группируем контроллеры с пространствами имён

В примере выше мы не использовали контроллеры, а возвращали статический текст. Можно добавить контроллеры с ещё одним «поворотом» — в результате получим структуризацию по папкам с их собственными пространствами имен:

2-20219-6b79a9.png

И сможем применить их в файле маршрутов:

Route::group([
'name' => 'front.',
'prefix' => 'front'
], function () {
Route::get('about-us', 'Front\AboutController@index')->name('about');
});

Но что произойдёт, если в данной группе будет много контроллеров? Потребуется ли постоянно добавлять Front\SomeController? Разумеется, нет. Вы просто указываете пространство имен в виде одного из параметров.

Route::group([
'name' => 'front.',
'prefix' => 'front',
'namespace' => 'Front',
], function () {
Route::get('about-us', 'AboutController@index')->name('about');
Route::get('contact', 'ContactController@index')->name('contact');
});

4. Группа в группе

Указанная выше ситуация с 3-мя группами упрощена. В действительности реальные проекты отличаются немного другой структурой, включающей в себя 2 группы: front и auth. И внутри auth существуют подгруппы: user и admin . Можно создать подгруппы в routes/web.php, а потом назначить разные мидлвары/префиксы и т. п.

Route::group([
'middleware' => 'auth',
], function() {

Route::group([
'name' => 'admin.',
'prefix' => 'admin',
'middleware' => 'admin'
], function () {

// адрес: /admin/users
// имя маршрута: admin.users
Route::get('users', 'UserController@index')->name('users');

});

Route::group([
'name' => 'user.',
'prefix' => 'user',
], function () {

// адрес: /user/profile
// имя маршрута: user.profile
Route::get('profile', 'ProfileController@index')->name('profile');

});

});

Мало того, можно сделать более, чем 2 уровня, как в примере из открытого проекта Akaunting:

Route::group(['middleware' => 'language'], function () {
Route::group(['middleware' => 'auth'], function () {
Route::group(['prefix' => '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' => 'permission:read-admin-panel'], function () {
Route::group(['prefix' => 'wizard'], function () {
Route::get('/', 'Wizard\Companies@edit')->name('wizard.index');

// ...

Или из проекта Monica:

Route::middleware(['auth', 'verified', 'mfa'])->group(function () {
Route::name('dashboard.')->group(function () {
Route::get('/dashboard', 'DashboardController@index')->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');
});

5. Глобальные настройки в RouteServiceProvider

Существует файл, настраивающий все маршруты — это app/Providers/RouteServiceProvider.php. В нём есть метод map(), благодаря которому оба файла маршрутов — web и API связываются:

public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}

protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}

protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}

Заметили ли вы, что в методах упоминается пространство имен, мидлвар и префикс? И здесь можно устанавливать глобальные настройки для маршрутов, тогда вам не придётся повторять их для каждой группы.

Как правило, данный файл используется для API-маршрутов, ведь их настройки обычно одинаковы:

protected function mapApiRoutes()
{
Route::group([
'middleware' => ['api'],
'namespace' => $this->namespace,
'prefix' => 'api/v1',
], function ($router) {
require base_path('routes/api.php');
});
}

А с помощью метода выше вы добавите префикс «api/v1/» для всех адресов API.

6. Группировка по файлам — стоит ли овчинка выделки?

Если у вас большое число маршрутов, и вы желаете ещё больше сгруппировать их в отдельные файлы, можно задействовать файл, упоминавшийся в предыдущем пункте — app/Providers/RouteServiceProvider.php.

Присмотревшись к методу map(), вы увидите в конце закомментированное место:

public function map()
{
$this->mapApiRoutes();

$this->mapWebRoutes();

//
}

Можно интерпретировать это, как в некотором роде «приглашение» и добавить ещё файлы, если пожелаете. Так вы сможете создать внутри файла ещё один метод, к примеру, mapAdminRoutes()с последующим добавлением его в метод map(). В итоге файл будет и зарегистрирован, и автоматически загружен.

С одной стороны, это даёт чуть большее разделение маршрутов, с другой — вы иногда теряетесь в этих файлах и пытаетесь вспомнить, где искать конкретный маршрут.

7. Находим точный маршрут с помощью Artisan route:list

В некоторых случаях нужный маршрут поможет найти artisan-команда. Скорее всего, вы в курсе, что php artisan route:list позволяет показать все маршруты в проекте:

3-20219-1e44a5.png

Но в курсе ли вы, что есть возможность фильтрации вывода с целью нахождения именно того, что надо? Для этого добавьте –method, либо –name, либо –path с параметрами.

Смотрим фильтрование по методу POST, GET, и т. д.

4-20219-1faaae.png

А вот фильтрование по части адреса или имени:

5-20219-16719f.png

Пожалуй, это всё, что можно рассказать о группировке маршрутов в крупных Laravel-проектах.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться