• Время чтения ~4 мин
  • 04.06.2022

Laravel Routing — это функция, которую разработчики изучают с самого начала. Но по мере того, как их проекты разрастаются, становится все труднее управлять постоянно растущими файлами маршрутов, прокручивая в поисках нужных операторов 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 используется для разных ролей пользователей, таких как Admin/HomeController и User/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() для подпапок контроллеров:

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