
Laravel 8: как удобно разделить роуты?
03.07.2021 11:30 | Laravel
Ubuntu: 20.04
PHP: 8.0.8
Laravel: 8.49.1
Начнём с того, что даже в небольших приложениях скорее всего будет админка, и ладно, если для пользовательской части используется SPA, т.е. роуты для неё находятся в файле api.php
. В этом случае маршруты админ-панели как и обычно могут распологатся в web.php
. Если же для всего приложения используется сугубо Laravel, то лучше вынести админ-роуты в отдельный файл.
Исходим из того, что мы хотим:
- чтобы у всех маршрутов админки был префикс admin. Например:
my-app.com/admin/login
,my-app.com/admin/customers
и т.д. - чтобы имя таких роутов также содержало префикс
admin
, т.е. мы могли вызывать роуты в приложении какroute('admin.dashboard')
илиroute('admin.customers.index')
и т.д.
Предположим, что файл с машрутизацией будет называться admin.php
. Идём в файл app/Providers/RouteServiceProvider.php
, и редактируем метод boot()
:
<?php
namespace App\Providers;
...
class RouteServiceProvider extends ServiceProvider
{
...
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
// Admin routes
Route::prefix('admin')
->name('admin.')
->middleware('web')
->group(base_path('routes/admin.php'));
});
}
...
}
В директории routes
создадим файл admin.php
:
<?php
use App\Http\Livewire\Admin\Login;
use App\Http\Livewire\Admin\CustomersList;
use App\Http\Livewire\Admin\Dashboard;
/** Admin routes examples */
Route::group(['middleware' => 'guest:admin'], function () {
Route::get('login', Login::class)->name('login');
});
Route::group(['middleware' => 'auth:admin'], function () {
Route::get('/', Dashboard::class)->name('dashboard');
Route::get('customers', CustomersList::class)->name('customers.index');
...
});
Примечание: предполагается, что у Вас есть middleware для проверки того, является ли пользователь админом. Также для примера в роутах используются компоненты Livewire, но всё то же самое справедливо и для контроллеров.
Теперь о средних и больших приложениях. Предположим у нас есть medium-size на Laravel, т.е. нам нужны web-маршруты для конечного пользователя и админ-панели. Кроме этого, есть мобильные приложения, для которых у нас есть API. Вероятнее всего, разделения на пару отдельных файлов бдует недостаточно. Лучше создать директории, каждая из которых будет содержать свои файлы. Структура директорий/файлов может выглядеть следующим образом:
my-app
...
routes
admin
customers.php
products.php
...
api
customers.php
products.php
...
web
customers.php
products.php
...
...
Помним о том, что каждой группе роутов может понадобится префикс к маршруту и имени, а также middleware. Снова идём в RouteServiceProvider
, добавим параметры групп:
private function getRouteParameters(): Collection
{
return collect([
'admin' => ['dir' => 'admin', 'prefix' => 'admin', 'name' => 'admin.', 'middleware' => 'web'],
'api' => ['dir' => 'api', 'prefix' => 'api', 'name' => 'api.', 'middleware' => 'api'],
'web' => ['dir' => 'web', 'prefix' => '', 'name' => '', 'middleware' => 'web'],
]);
}
Также нужен будет метод который будет обрабатывать файлы маршрутов отдельной директории:
private function mapRoutes($params)
{
collect(File::files(base_path('routes/'.$params['dir'])))->each(function ($file) use ($params) {
Route::prefix($params['prefix'])
->name($params['name'])
->middleware($params['middleware'])
->namespace($this->namespace)
->group($file);
});
}
...и завершающий шаг - модификация метода boot()
:
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
$this->getRouteParameters()->each(function ($params) {
$this->mapRoutes($params);
});
});
}
В конечно итоге наш app/Providers/RouteServiceProvider.php
будет выглядеть так:
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
public const HOME = '/dashboard';
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
$this->getRouteParameters()->each(function ($params) {
$this->mapRoutes($params);
});
});
}
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});
}
private function mapRoutes($params)
{
collect(File::files(base_path('routes/'.$params['dir'])))->each(function ($file) use ($params) {
Route::prefix($params['prefix'])
->name($params['name'])
->middleware($params['middleware'])
->namespace($this->namespace)
->group($file);
});
}
private function getRouteParameters(): Collection
{
return collect([
'admin' => ['dir' => 'admin', 'prefix' => 'admin', 'name' => 'admin.', 'middleware' => 'web'],
'api' => ['dir' => 'api', 'prefix' => 'api', 'name' => 'api.', 'middleware' => 'api'],
'web' => ['dir' => 'web', 'prefix' => '', 'name' => '', 'middleware' => 'web'],
]);
}
}
На этом на сегодня всё. Успехов!