• Час читання ~4 хв
  • 04.06.2022

Маршрутизація Laravel – це функція, яку розробники вивчають із самого початку. Але в міру зростання їхніх проектів стає все важче керувати файлами маршрутів, що постійно зростають, прокручуючи, щоб знайти правильні інструкції Route::get(). На щастя, існують методи, які дозволяють зробити файли маршрутів коротшими та читабельнішими, групуючи маршрути та їх налаштування різними способами. Давайте подивимось.

І ні, я не буду говорити лише про загальний простий Route::group(), це рівень для початківців. Давайте зануримося трохи глибше.


Групування 1. Route::resource і Route::apiResource

Почнемо зі слона в кімнаті: це, мабуть, найвідоміше угруповання.Якщо у вас є типовий набір дій CRUD навколо однієї моделі, варто згрупувати їх у контролер ресурсів

Такий контролер може складатися з до 7 методів (але може мати менше):

  • index()
  • create()
  • store()
  • show()
  • edit()
  • update()
  • destroy()

Тож якщо ваш набір маршрутів відповідає цим методам, а не:

Route::get('books', [BookController::class, 'index'])->name('books.index');
Route::get('books/create', [BookController::class, 'create'])->name('books.create');
Route::post('books', [BookController::class, 'store'])->name('books.store');
Route::get('books/{book}', [BookController::class, 'show'])->name('books.show');
Route::get('books/{book}/edit', [BookController::class, 'edit'])->name('books.edit');
Route::put('books/{book}', [BookController::class, 'update'])->name('books.update');
Route::delete('books/{book}', [BookController::class, 'destroy'])->name('books.destroy');

...у вас може бути лише один рядок:

Route::resource('books', BookController::class);

Якщо ви працюєте з проектом API, вам не потрібні візуальні форми для створення/редагування, тому ви можете мати інший синтаксис з apiResource(), який охоплює 5 методів із 7 :

Route::apiResource('books', BookController::class);

Крім того, я раджу вам розглянути контролери ресурсів, навіть якщо у вас є 2-4 методи, а не 7 повних.Просто тому, що він дотримується стандартної конвенції про іменування - для URL-адрес, методів і назв маршрутів. Наприклад, у цьому випадку вам не потрібно вводити імена вручну:

Route::get('books/create', [BookController::class, 'create'])->name('books.create');
Route::post('books', [BookController::class, 'store'])->name('books.store');
 
// Instead, here names "books.create" and "books.store" are assigned automatically
Route::resource('books', BookController::class)->only(['create', 'store']);

Групування 2. Групування всередині групи

Звичайно, всі знають про загальне групування маршрутів.Але для більш складних проектів одного рівня групування може бути недостатньо.

Реалістичний приклад: ви хочете, щоб авторизовані маршрути були згруповані за допомогою проміжного програмного забезпечення auth, але всередині вам потрібно розділити більше підгруп, наприклад адміністратора та простого користувача.

Route::middleware('auth')->group(function() {
 
    Route::middleware('is_admin')->prefix('admin')->group(function() {
    	Route::get(...) // administrator routes
    });
 
    Route::middleware('is_user')->prefix('user')->group(function() {
    	Route::get(...) // user routes
    });
});

Групування 3.Повторення проміжного програмного забезпечення в групу

Що робити, якщо у вас досить багато проміжного програмного забезпечення, деякі з яких повторюються в кількох групах маршрутів?

Route::prefix('students')->middleware(['auth', 'check.role', 'check.user.status', 'check.invoice.status', 'locale'])->group(function () {
    // ... student routes
});
 
Route::prefix('managers')->middleware(['auth', 'check.role', 'check.user.status', 'locale'])->group(function () {
    // ... manager routes
});

Як бачите, існує 5 проміжних програм, 4 з яких повторюються. Отже, ми можемо перемістити ці 4 в окрему групу проміжного програмного забезпечення у файлі app/Http/Kernel.php:

protected $middlewareGroups = [
    // This group comes from default Laravel
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
 
    // This group comes from default Laravel
    'api' => [
        // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
 
    // THIS IS OUR NEW MIDDLEWARE GROUP
    'check_user' => [
        'auth',
        'check.role',
        'check.user.status',
        'locale'
    ],
];

Тому ми назвали нашу групу check_user, і тепер ми можемо скоротити маршрути:

Route::prefix('students')->middleware(['check_user', 'check.invoice.status'])->group(function () {
    // ... student routes
});
 
Route::prefix('managers')->middleware(['check_user'])->group(function () {
    // ... manager routes
});

Групування 4. Контролери з однаковими іменами, різні простори імен

Досить поширеною ситуацією є наявність, наприклад, HomeController для різних ролей користувачів, наприклад Адміністратор/HomeController і Користувач/HomeController.А якщо ви використовуєте повний шлях у своїх маршрутах, він виглядає приблизно так:

Route::prefix('admin')->middleware('is_admin')->group(function () {
    Route::get('home', [\App\Http\Controllers\Admin\HomeController::class, 'index']);
});
 
Route::prefix('user')->middleware('is_user')->group(function () {
    Route::get('home', [\App\Http\Controllers\User\HomeController::class, 'index']);
});

Досить багато коду для введення за цими повними шляхами, чи не так? Ось чому багато розробників вважають за краще мати лише HomeController::class у списку маршрутів і додати щось на зразок цього зверху:

use App\Http\Controllers\Admin\HomeController;

Але проблема в тому, що ми маємо однакову назву класу контролера!Отже, це не спрацює:

use App\Http\Controllers\Admin\HomeController;
use App\Http\Controllers\User\HomeController;

Який із них буде "офіційним"? Ну, один із способів – змінити ім’я та призначити псевдонім для одного з них:

use App\Http\Controllers\Admin\HomeController as AdminHomeController;
use App\Http\Controllers\User\HomeController;
 
Route::prefix('admin')->middleware('is_admin')->group(function () {
    Route::get('home', [AdminHomeController::class, 'index']);
});
 
Route::prefix('user')->middleware('is_user')->group(function () {
    Route::get('home', [HomeController::class, 'index']);
});

Але, особисто, зміна назви класу зверху для мене досить заплутана, мені подобається інший підхід: додати namespace() для підпапок Controllers:

Route::prefix('admin')->namespace('App\Http\Controllers\Admin')->middleware('is_admin')->group(function () {
    Route::get('home', [HomeController::class, 'index']);
    // ... other controllers from Admin namespace
});
 
Route::prefix('user')->namespace('App\Http\Controllers\User')->middleware('is_user')->group(function () {
    Route::get('home', [HomeController::class, 'index']);
    // ... other controllers from User namespace
});

Групування 5.Окремі файли маршрутів

Якщо ви відчуваєте, що ваш основний routes/web.php або routes/api.php стає занадто великим, ви можете взяти деякі з маршрутів і помістити їх у окремим файлом, іменуйте їх так, як хочете, наприклад routes/admin.php.

Тоді, щоб включити цей файл, у вас є два способи: я називаю «спосіб Laravel» і «спосіб PHP».

Якщо ви хочете прослідкувати структуру того, як Laravel структурує свої файли маршрутів за замовчуванням, це відбувається в app/Providers/RouteServiceProvider.php:

public function boot()
{
    $this->configureRateLimiting();
 
    $this->routes(function () {
        Route::middleware('api')
            ->prefix('api')
            ->group(base_path('routes/api.php'));
 
        Route::middleware('web')
            ->group(base_path('routes/web.php'));
    });
}

Як бачите, і routes/api.php, так і routes/web.php знаходяться тут із дещо різними налаштуваннями.Отже, все, що вам потрібно зробити, це додати сюди свій файл адміністратора:

$this->routes(function () {
    Route::middleware('api')
        ->prefix('api')
        ->group(base_path('routes/api.php'));
 
    Route::middleware('web')
        ->group(base_path('routes/web.php'));
 
    Route::middleware('is_admin')
        ->group(base_path('routes/admin.php'));
});

Але якщо ви не хочете занурюватися в постачальників послуг, є коротший шлях - просто включіть/вимагайте маршрутизує файл в інший файл, як ви це робите в будь-якому файлі PHP, поза межами Laravel.

Route::get('/', function () {
    return view('welcome');
});
 
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');
 
require __DIR__.'/auth.php';

Route::get('profile', [ProfileController::class, 'getProfile']);
Route::put('profile', [ProfileController::class, 'updateProfile']);
Route::delete('profile', [ProfileController::class, 'deleteProfile']);
Route::controller(ProfileController::class)->group(function() {
    Route::get('profile', 'getProfile');
    Route::put('profile', 'updateProfile');
    Route::delete('profile', 'deleteProfile');
});

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297