Challenge 1: Write and Apply Custom Middleware — Possible Solution ==================================================================== # php artisan make:middleware EnsureBookstoreIsOpen // app/Http/Middleware/EnsureBookstoreIsOpen.php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; class EnsureBookstoreIsOpen { public function handle(Request $request, Closure $next) { $currentHour = (int) date('G'); // 0-23, simulate/replace with a fixed value for testing if ($currentHour < 9 || $currentHour >= 17) { return response('The bookstore is currently closed. Please come back between 9am and 5pm.', 503); } return $next($request); } } // bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'store.open' => \App\Http\Middleware\EnsureBookstoreIsOpen::class, ]); }) // routes/web.php — scoped to /orders only, NOT applied globally Route::prefix('orders')->middleware('store.open')->group(function () { Route::get('/', [OrderController::class, 'index'])->name('orders.index'); Route::post('/', [OrderController::class, 'store'])->name('orders.store'); }); // Routes OUTSIDE this group (e.g. /books, /authors) are completely // unaffected by this middleware — visiting them works regardless of the // time of day. WHY THIS WORKS -------------- - The middleware checks the condition FIRST and returns an early response(..., 503) WITHOUT ever calling $next($request) when the bookstore is "closed" — this is the correct way to intentionally short-circuit the pipeline (as opposed to Chapter 8's gotcha, which warns about accidentally forgetting $next() when you DID intend to let the request continue). - When the condition passes (bookstore is open), the middleware calls return $next($request) — passing control forward to whatever's next in the pipeline, ultimately reaching the route's controller. - Applying ->middleware('store.open') specifically to the Route::prefix('orders')->group(...) block means this check ONLY runs for requests under /orders — routes for books, authors, or anything else defined elsewhere in routes/web.php never invoke this middleware at all, exactly the deliberate, route-specific scoping the chapter contrasts against Django's global-by-default MIDDLEWARE list.