Challenge 1: Cache an Expensive Query — Possible Solution ==================================================================== // app/Http/Controllers/BookController.php use Illuminate\Support\Facades\Cache; use App\Models\Book; public function stats() { $stats = Cache::remember('book_stats', 600, function () { return [ 'total' => Book::count(), 'average_price' => Book::avg('price'), ]; }); return view('books.stats', ['stats' => $stats]); } WHY THIS WORKS -------------- - Cache::remember('book_stats', 600, function () { ... }) checks for an existing 'book_stats' cache entry first; if it's missing or expired, it runs the closure ONCE, stores the result under that key for 600 seconds (10 minutes), and returns it — all in one call, exactly the same check-then-compute-then-store pattern as Django's cache.get_or_set(). - Within that 10-minute window, every subsequent call to Cache::remember('book_stats', ...) returns the cached array instantly without running Book::count() or Book::avg('price') again — those two separate database queries only actually execute roughly once every 10 minutes, regardless of how many requests hit this method in between. - The closure (function () { ... }) is only invoked if the cache is actually missing — Cache::remember() doesn't eagerly run it just to check whether its result should be discarded, mirroring exactly how Django's get_or_set() treats its callback argument.