• Czas czytania ~4 min
  • 04.06.2022

Laravel Routing to funkcja, której programiści uczą się od samego początku. Jednak wraz z rozwojem ich projektów coraz trudniej jest zarządzać stale rosnącymi plikami tras, przewijając w celu znalezienia właściwych instrukcji Route::get(). Na szczęście istnieją techniki, dzięki którym pliki tras są krótsze i bardziej czytelne, grupując trasy i ich ustawienia na różne sposoby. Spójrzmy.

I nie, nie będę mówić tylko o ogólnym prostym Route::group(), który jest poziomem początkującym. Zanurzmy się nieco głębiej.


Grupowanie 1. Route::resource i Route::apiResource

Zacznijmy od słonia w pokoju: to prawdopodobnie najbardziej znana grupa.Jeśli masz typowy zestaw akcji CRUD wokół jednego modelu, warto pogrupować je w kontroler zasobów

Taki kontroler może składać się z do 7 metod (ale może mieć mniej):

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

Jeśli więc Twój zestaw tras odpowiada tym metodom, zamiast:

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');

...możesz mieć tylko jedną linię:

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

Jeśli pracujesz z projektem API, nie potrzebujesz wizualnych formularzy do tworzenia/edycji, więc możesz mieć inną składnię z apiResource(), która obejmowałaby 5 z 7 metod :

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

Również radzę wziąć pod uwagę kontrolery zasobów, nawet jeśli masz 2-4 metody, a nie pełne 7.Tylko dlatego, że zachowuje standardową konwencję nazewnictwa — dla adresów URL, metod i nazw tras. Na przykład w tym przypadku nie musisz podawać nazw ręcznie:

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']);

Grupowanie 2. Grupuj w grupie

Oczywiście wszyscy wiedzą o ogólnym grupowaniu tras.Ale w przypadku bardziej złożonych projektów jeden poziom grupowania może nie wystarczyć.

Realistyczny przykład: chcesz, aby autoryzowane trasy były grupowane z oprogramowaniem pośredniczącym auth, ale wewnątrz musisz oddzielić więcej podgrup, takich jak administrator i prosty użytkownik.

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
    });
});

Grupowanie 3.Powtarzanie oprogramowania pośredniczącego w grupie

Co zrobić, jeśli masz dość dużo oprogramowania pośredniego, niektóre z nich powtarzają się w kilku grupach tras?

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
});

Jak widać, istnieje 5 programów pośredniczących, z których 4 się powtarzają. Możemy więc przenieść te 4 do osobnej grupy oprogramowania pośredniego, w pliku 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'
    ],
];

Więc nazwaliśmy naszą grupę check_user i teraz możemy skrócić trasy:

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

Grupowanie 4. Kontrolery o tej samej nazwie, różne przestrzenie nazw

Całkiem powszechną sytuacją jest posiadanie, na przykład, HomeController dla różnych ról użytkownika, takich jak Admin/HomeController i User/HomeController.A jeśli użyjesz pełnej ścieżki w swoich trasach, wygląda to mniej więcej tak:

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']);
});

Dość dużo kodu do wpisania z tymi pełnymi ścieżkami, prawda? Dlatego wielu programistów woli mieć tylko HomeController::class na liście tras i dodać coś takiego na górze:

use App\Http\Controllers\Admin\HomeController;

Ale problem polega na tym, że mamy tę samą nazwę klasy kontrolera!Więc to by nie zadziałało:

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

Który byłby „oficjalnym”? Cóż, jednym ze sposobów jest zmiana nazwy i przypisanie aliasu do jednego z nich:

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']);
});

Ale osobiście zmiana nazwy klasy na górze jest dla mnie dość myląca, lubię inne podejście: dodać namespace() dla podfolderów kontrolerów:

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
});

Grupowanie 5.Oddzielne pliki tras

Jeśli uważasz, że główne trasy/web.php lub routes/api.php stają się zbyt duże, możesz skorzystać z niektórych tras i umieścić je w oddzielny plik, nazwij je jak chcesz, np. routes/admin.php.

Następnie, aby umożliwić uwzględnienie tego pliku, masz dwa sposoby: nazywam „sposób Laravela” i „sposób PHP”.

Jeśli chcesz śledzić strukturę tego, jak Laravel tworzy swoje domyślne pliki tras, dzieje się to w 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'));
    });
}

Jak widać, zarówno routes/api.php jak i routes/web.php są tutaj, z nieco innymi ustawieniami.Wszystko, co musisz zrobić, to dodać tutaj swój plik administratora:

$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'));
});

Ale jeśli nie chcesz zagłębiać się w dostawców usług, istnieje krótsza droga — wystarczy uwzględnić/wymagać kieruje plik do innego pliku, tak jak robisz to w dowolnym pliku PHP, poza frameworkiem 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

O

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...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297