lotestudio / model-cache
Model cache package for Laravel
Requires
- php: ^8.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^7.0|^8.0
README
Under development! Use at your own risk!
A lightweight, convention-driven caching layer for Laravel Eloquent models. Automatically caches model query results with observer-based invalidation, request-level caching, and Artisan commands for management.
Designed to cache frequently accessed reference data like stores, price lists, categories, and roles. It's ideal for small datasets (under 50 records) that are read often but change rarely, dramatically reducing database queries and improving response times from ~5-10ms to under 1ms.
Use it when: you have lookup tables, reference data, or configuration-like models that are loaded on almost every request and don't change frequently.
Avoid it when: you're dealing with large tables (>100 records), frequently changing data, real-time requirements, or models with heavy JSON fields that consume significant memory.
Best for: Stores, price lists, categories, statuses, roles, and other "dictionary" tables that power your application's dropdowns, filters, and navigation.
Not suitable for: Orders, users, logs, products (if large), or any data that requires up-to-the-second accuracy.
The package includes automatic cache clearing via observers, request-level caching, Artisan commands, and full Eloquent model support — everything stays cached while maintaining Laravel's native behavior.
Features
- Automatic Caching — Cache model query results with configurable TTL and cache driver
- Observer-Based Invalidation — Automatically clears cache when models are saved, updated, deleted, or restored
- Request-Level Caching — Avoids redundant cache lookups within the same request
- Artisan Commands — Warm up, clear, and inspect cache statistics via CLI
- Helper Functions — Convenient global helpers for quick access
- Facade Support —
ModelCachefacade for dependency injection - Dynamic Magic Methods — Call
findStores($id),allStores(), etc. directly - Fallback to Database — Gracefully falls back to database queries when cache is empty
Requirements
- PHP 8.4+
- Laravel 12+
Installation
The package is located at Lotestudio/ModelCache and is auto-discovered via Laravel's service provider registration.
Service Provider
Register the service provider in bootstrap/providers.php (Laravel 12) or config/app.php:
Lotestudio\ModelCache\ModelCacheServiceProvider::class,
Facade (Optional)
Add to the aliases array in config/app.php:
'ModelCache' => Lotestudio\ModelCache\Facades\ModelCache::class,
Configuration
Publish the configuration file:
php artisan vendor:publish --provider="Lotestudio\ModelCache\ModelCacheServiceProvider" --tag="model-cache-config"
return [ 'driver' => env('MODEL_CACHE_DRIVER', env('CACHE_DRIVER', 'file')), 'ttl' => env('MODEL_CACHE_TTL', 86400), // 24 hours 'prefix' => env('MODEL_CACHE_PREFIX', 'model_cache_'), 'models' => [ 'stores' => [ 'model' => App\Models\Store::class, 'key' => 'stores', 'ttl' => 86400, 'order_by' => 'name', 'order_direction' => 'asc', 'fields' => ['id', 'name', 'address', 'phone', 'is_active'], 'conditions' => [ ['is_active', '=', true], ], ], ], 'auto_clear' => true, 'warmup_on_boot' => env('MODEL_CACHE_WARMUP', false), 'logging' => env('MODEL_CACHE_LOGGING', false), 'use_tags' => env('MODEL_CACHE_TAGS', false), 'request_cache' => true, 'fallback_to_db' => true, 'id_field' => 'id', ];
Model Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
model |
string |
required | Full class name of the Eloquent model |
key |
string |
required | Unique cache key identifier |
ttl |
int |
86400 |
Cache TTL in seconds |
order_by |
string |
— | Column to order results by |
order_direction |
string |
'asc' |
Sort direction (asc or desc) |
fields |
array |
null (all) |
Specific columns to select |
conditions |
array |
[] |
Where clauses [['column', 'operator', value], ...] |
Usage
Basic Usage
use Lotestudio\ModelCache\Facades\ModelCache; // Get all cached stores $stores = ModelCache::all('stores'); // Find a specific store by ID $store = ModelCache::find('stores', 1); // Find by custom field $store = ModelCache::findBy('stores', 'email', 'admin@example.com'); // Find all matching a condition $activeStores = ModelCache::findAllBy('stores', 'is_active', true); // Check existence if (ModelCache::exists('stores', 1)) { // ... } // Clear cache for a specific model ModelCache::clear('stores'); // Clear all caches ModelCache::clearAll(); // Warm up cache ModelCache::warmup('stores'); ModelCache::warmupAll();
Dynamic Magic Methods
The __call magic method provides convenient shortcuts:
// Equivalent to ModelCache::find('stores', $id) ModelCache::findStores($id); // Equivalent to ModelCache::all('stores') ModelCache::allStores(); // Equivalent to ModelCache::clear('stores') ModelCache::clearStores();
Helper Functions
// Get the cache instance $cache = model_cache(); // Find a cached model by ID $store = model_cached('stores', 1); // Get all cached models $stores = model_cached_all('stores'); // Find by custom field $store = model_cached_find_by('stores', 'slug', 'main-store'); // Find all matching $items = model_cached_find_all_by('stores', 'is_active', true); // Check existence $exists = model_cached_exists('stores', 1); // Clear cache model_cache_clear('stores'); model_cache_clear_all(); // Warm up cache model_cache_warmup('stores'); model_cache_warmup_all(); // Get statistics $stats = model_cache_stats(); $storeStats = model_cache_stats('stores'); // Register a model dynamically model_cache_register('products', [ 'model' => App\Models\Product::class, 'key' => 'products', 'order_by' => 'name', ]);
Using the Interface (Dependency Injection)
use Lotestudio\ModelCache\Contracts\ModelCacheInterface; class StoreController { public function __construct( protected ModelCacheInterface $cache ) {} public function index() { $stores = $this->cache->all('stores'); return view('stores.index', compact('stores')); } }
Artisan Commands
Warm Up Cache
# Warm up all registered models php artisan model-cache:warmup # Warm up a specific model php artisan model-cache:warmup --key=stores # Force re-cache (clear then warm up) php artisan model-cache:warmup --key=stores --force # Show detailed output php artisan model-cache:warmup --verbose
Clear Cache
# Clear all model caches php artisan model-cache:clear --all # Clear a specific model cache php artisan model-cache:clear --key=stores
Cache Statistics
# Show overall statistics php artisan model-cache:stats # Show per-model statistics php artisan model-cache:stats --key=stores
Observer-Based Auto-Clear
When auto_clear is enabled in the config, the package automatically registers model observers that clear the relevant cache whenever a model is saved, updated, deleted, or restored.
The service provider checks for a custom observer at App\Observers\{ModelName}Observer before falling back to the generic ModelCacheObserver.
Architecture
Lotestudio/ModelCache/
├── Commands/
│ ├── CacheClearCommand.php # php artisan model-cache:clear
│ ├── CacheStatsCommand.php # php artisan model-cache:stats
│ └── CacheWarmupCommand.php # php artisan model-cache:warmup
├── Contracts/
│ └── ModelCacheInterface.php # Interface contract
├── Facades/
│ └── ModelCache.php # Facade accessor
├── config/
│ └── model-cache.php # Configuration
├── ModelCache.php # Core implementation
├── ModelCacheObserver.php # Generic model observer
├── ModelCacheServiceProvider.php # Service provider
└── helpers.php # Global helper functions
Cache Invalidation
Cache is automatically invalidated via model observers when:
saved— Model is created or updatedupdated— Model is updateddeleted— Model is deletedrestored— Model is restored from soft delete
Manual invalidation is also available via clear() or the Artisan command.
License
This is internal application code. All rights reserved.