vigstudio/laravel-eloquent-query-cache
Add query-level caching back to Eloquent with a simple remember-like API. Cache results from database queries, reduce repeated hits, and integrate with Laravel’s cache stores for faster reads and configurable invalidation.
Installation
composer require vigstudio/laravel-eloquent-query-cache
Publish the config file (optional):
php artisan vendor:publish --provider="Vigstudio\EloquentQueryCache\EloquentQueryCacheServiceProvider" --tag="config"
Basic Usage
Enable caching for a query by adding cache() to your Eloquent query:
$users = User::cache(60)->get(); // Cache results for 60 seconds
Subsequent identical queries within the TTL will return cached results.
First Use Case Optimize a frequently accessed but computationally expensive query (e.g., dashboard metrics):
$stats = Analytics::cache(300)->where('period', 'daily')->get();
Cache Entire Queries
$posts = Post::with('author')->cache(3600)->orderBy('created_at', 'desc')->paginate(10);
Cache includes relationships and pagination.
Conditional Caching
Use when() to conditionally apply caching:
$query = User::query();
if ($request->has('cache')) {
$query->cache(300);
}
$users = $query->get();
User::cache()->forget(); // Clears all cached User queries
User::cache()->forget(['active' => true]); // Clears cached queries with this where clause
saved, deleted) to invalidate related caches:
User::saved(function ($user) {
User::cache()->forget(['id' => $user->id]);
});
Dynamic TTL Set TTL based on runtime logic:
$ttl = $isAdmin ? 86400 : 300; // 24h for admins, 5m for guests
$users = User::cache($ttl)->get();
Cache Tags Use tags for granular invalidation (requires config):
User::cache(300)->tag('users:active')->get();
User::cache()->forgetTag('users:active');
Fallback to Database Force a fresh query if cache is stale or missing:
$users = User::cache(300, true)->get(); // `true` = force fresh if cache misses
Cache Key Collisions
The package generates keys using the query's toSql() and bindings. Avoid identical queries with different logic (e.g., where('active', 1) vs. where('active', true)). Use explicit keys if needed:
User::cache(300, 'custom:key')->get();
Relationship Caching Quirks
Cached relationships (with()) are serialized. Avoid caching relationships with:
Pagination Caching
Cached pagination (paginate()) includes the current_page in the cache key. Ensure consistent pagination parameters across requests.
Database Schema Changes Schema changes (e.g., column renames) can break cached queries. Invalidate all caches after migrations:
php artisan cache:clear
User::cache()->flush(); // Clear all Eloquent query caches
Inspect Cache Keys Log the generated cache key to debug collisions:
$key = User::cache(300)->getCacheKey();
\Log::info('Cache key:', [$key]);
Disable Caching Temporarily
Set TTL to 0 or use the forceFresh flag to bypass cache:
User::cache(0)->get(); // Disables caching
User::cache(300, true)->get(); // Forces fresh data
Check Cache Storage
Verify the cache driver (e.g., file, redis) is configured in .env:
CACHE_DRIVER=redis
Default TTL
Set a default TTL in config/eloquent-query-cache.php:
'default_ttl' => 60, // Default: 60 seconds
Cache Prefix Customize the cache prefix to avoid conflicts:
'prefix' => 'eloquent_queries_',
Excluded Models Disable caching for specific models:
'excluded_models' => [
'App\Models\UncacheableModel',
],
Custom Cache Drivers
Extend the package to support custom cache backends by implementing Vigstudio\EloquentQueryCache\Contracts\CacheDriver.
Query Filtering
Override the shouldCache() method in a model to dynamically enable/disable caching:
class User extends Model
{
public function shouldCache()
{
return auth()->check() && $this->isPopular();
}
}
Cache Warmers Pre-warm caches during low-traffic periods (e.g., cron jobs):
User::cache(86400)->get(); // Warm popular queries
How can I help you explore Laravel packages today?