
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.dashboard.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'],
]);
}
}
На цьому на сьогодні все. Успіхів!