6 个组织路由的技巧
最后更新于 作者: PovilasKorop
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()` 的不同语法,它将涵盖 7 种方法中的 5 种。
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 automaticallyRoute::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 框架之外那样,直接将你的路由文件包含/要求到另一个文件中。
事实上,它是由 Taylor Otwell 本人完成的,将 `routes/auth.php` 文件直接要求到 Laravel Breeze 路由 中。
routes/web.php:
Route::get('/', function () { return view('welcome');}); Route::get('/dashboard', function () { return view('dashboard');})->middleware(['auth'])->name('dashboard'); require __DIR__.'/auth.php';
分组 6. Route::controller()
如果你在控制器中有一些方法,但它们不遵循标准的资源结构,你仍然可以将它们分组,而无需为每个方法重复控制器名称。
而不是
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');});
就是这样,这些是分组技术,希望它们能帮助你组织和维护你的路由,无论你的项目规模有多大。