Laravel 6.x如何避免重复/{storeId}路由?实现指定格式URL
Hey there! Let's clean up that repetitive {storeId} in your Laravel 6.x routes—this is a super common scenario for multi-store dashboards, and we can fix it neatly without repeating the parameter every time.
Here's the step-by-step solution:
1. Nest your store-specific routes in a prefix group
Instead of adding {storeId} to every resource route, wrap all store-specific routes in a parent route group with the prefix('{storeId}') attribute. This will automatically prepend the storeId parameter to all child routes.
Route::middleware('auth')->group(function () { // Routes for store selection (no storeId prefix needed) Route::resource('stores', 'StoreController'); // Nested group for all store-specific routes Route::prefix('{storeId}') ->middleware('store.access') // We'll add this middleware next ->group(function () { // Add your store dashboard home route Route::get('home', 'StoreDashboardController@index')->name('store.home'); // Your existing resource routes, now without repeating {storeId} Route::resource('warehouse', 'WarehouseController'); Route::resource('employees', 'EmployeesController'); }); });
2. Add a middleware to validate store access
You'll want to ensure the logged-in user actually owns or has permission to access the store specified by storeId. Create a custom middleware to handle this:
// app/Http/Middleware/StoreAccess.php namespace App\Http\Middleware; use Closure; use App\Store; class StoreAccess { public function handle($request, Closure $next) { // Fetch the store or throw a 404 if it doesn't exist $store = Store::findOrFail($request->storeId); // Verify the logged-in user has access to this store if (!$request->user()->stores->contains($store->id)) { abort(403, "You don't have permission to access this store."); } // Attach the valid store instance to the request for easy use in controllers $request->merge(['store' => $store]); return $next($request); } }
Register this middleware in your Kernel.php:
// app/Http/Kernel.php protected $routeMiddleware = [ // ... existing middleware entries 'store.access' => \App\Http\Middleware\StoreAccess::class, ];
3. Use the store instance in your controllers
Now that the middleware validates and attaches the store to the request, you can easily access it in your controllers without re-fetching:
// app/Http/Controllers/WarehouseController.php use Illuminate\Http\Request; class WarehouseController extends Controller { public function index(Request $request) { // Get the pre-validated store from the request $store = $request->store; // Fetch warehouse data specific to this store $warehouses = $store->warehouses; return view('warehouse.index', compact('warehouses')); } }
Bonus: Implicit Model Binding (optional but cleaner)
For even more Laravel-style elegance, use implicit model binding. Change the route parameter from {storeId} to {store}—Laravel will automatically fetch the Store instance for you, no need for findOrFail in the middleware:
// Update the route group prefix Route::prefix('{store}') ->middleware('store.access') ->group(function () { // ... your routes }); // Update the middleware to use the auto-fetched store public function handle($request, Closure $next) { if (!$request->user()->stores->contains($request->store->id)) { abort(403); } return $next($request); }
Why this works:
- You avoid repeating
{storeId}across every route - The
store.accessmiddleware ensures only authorized users access each store's dashboard - Routes will follow your desired pattern:
http://127.0.0.1:8000/{storeId}/home,http://127.0.0.1:8000/{storeId}/warehouse, etc. - Generating URLs is still straightforward:
route('warehouse.index', ['storeId' => $store->id])
内容的提问来源于stack exchange,提问作者Rafael Breno

