iazaran / smart-cache
Smart Cache is a caching optimization package designed to enhance the way your Laravel application handles data caching. It intelligently manages large data sets by compressing, chunking, or applying other optimization strategies to keep your application performant and efficient.
Requires
- php: ^8.1
- illuminate/cache: ^8.0||^9.0||^10.0||^11.0||^12.0
- illuminate/console: ^8.0||^9.0||^10.0||^11.0||^12.0
- illuminate/contracts: ^8.0||^9.0||^10.0||^11.0||^12.0
- illuminate/support: ^8.0||^9.0||^10.0||^11.0||^12.0
Requires (Dev)
- mockery/mockery: ^1.5
- orchestra/testbench: ^6.0||^7.0||^8.0||^9.0||^10.0
- phpunit/phpunit: ^9.0|^10.0|^11.0
- symfony/var-dumper: ^5.4|^6.0|^7.0
README
Drop-in replacement for Laravel's Cache facade that automatically compresses, chunks, and optimizes cached data — with write deduplication, self-healing recovery, and cost-aware eviction built in.
Implements Illuminate\Contracts\Cache\Repository and PSR-16 SimpleCache. Your existing code works unchanged.
PHP 8.1+ · Laravel 8–12 · Redis, File, Database, Memcached, Array
Installation
composer require iazaran/smart-cache
That's it. No configuration required — works immediately with your existing cache driver.
Quick Start
use SmartCache\Facades\SmartCache; // Same API you already know SmartCache::put('users', $users, 3600); $users = SmartCache::get('users'); // Remember pattern — with automatic compression & cost tracking $users = SmartCache::remember('users', 3600, fn() => User::all()); // Helper function smart_cache(['products' => $products], 3600); $products = smart_cache('products');
Large data is automatically compressed and chunked behind the scenes. No code changes needed.
Why SmartCache?
| Problem | Without SmartCache | With SmartCache |
|---|---|---|
| Large payloads (100 KB+) | Stored as-is, slow reads | Auto-compressed & chunked |
| Redundant writes | Every put() hits the store |
Skipped when unchanged (write deduplication) |
| Corrupted entries | Exception crashes the request | Auto-evicted and regenerated (self-healing) |
| Eviction decisions | LRU / random | Cost-aware scoring — keeps high-value keys |
| Cache stampede | Thundering herd on expiry | XFetch, jitter, and rate limiting |
| Conditional caching | Manual if around put() |
rememberIf() — one-liner |
| Stale data serving | Not available | SWR, stale, refresh-ahead, async queue refresh |
| Observability | DIY logging | Built-in dashboard, metrics, and health checks |
How Automatic Optimization Works
SmartCache selects the best strategy based on your data — zero configuration:
| Data Profile | Strategy Applied | Effect |
|---|---|---|
| Arrays with 5 000+ items | Chunking | Lower memory, faster access |
| Serialized data > 50 KB | Compression | Significant size reduction (gzip) |
| API responses > 100 KB | Chunking + Compression | Best of both |
| Data < 50 KB | None | Zero overhead |
All thresholds are configurable.
Features
Every feature below is opt-in and backward-compatible.
Multiple Cache Drivers
// Each store preserves all SmartCache optimizations SmartCache::store('redis')->put('key', $value, 3600); SmartCache::store('memcached')->remember('users', 3600, fn() => User::all()); // Bypass SmartCache when needed SmartCache::repository('redis')->put('key', $value, 3600);
SWR Patterns (Stale-While-Revalidate)
// Serve stale data while refreshing in background $data = SmartCache::swr('github_repos', fn() => Http::get('...')->json(), 300, 900); // Extended stale serving (1 h fresh, 24 h stale) $config = SmartCache::stale('site_config', fn() => Config::fromDatabase(), 3600, 86400); // Proactive refresh before expiry $analytics = SmartCache::refreshAhead('daily_analytics', fn() => Analytics::generateReport(), 1800, 300); // Queue-based background refresh — returns stale immediately $data = SmartCache::asyncSwr('dashboard_stats', fn() => Stats::generate(), 300, 900, 'cache-refresh');
Stampede Protection
// XFetch algorithm — probabilistic early refresh $data = SmartCache::rememberWithStampedeProtection('key', 3600, fn() => expensiveQuery()); // Rate-limited regeneration SmartCache::throttle('api_call', 10, 60, fn() => expensiveApiCall()); // TTL jitter — prevents thundering herd on expiry SmartCache::withJitter(0.1)->put('popular_data', $data, 3600); // Actual TTL: 3240–3960 s (±10 %)
Write Deduplication (Cache DNA)
Hashes every value before writing. Identical content → write skipped entirely.
SmartCache::put('app_config', Config::all(), 3600); SmartCache::put('app_config', Config::all(), 3600); // no I/O — data unchanged
Self-Healing Cache
Corrupted entries are auto-evicted and regenerated on next read — zero downtime.
$report = SmartCache::remember('report', 3600, fn() => Analytics::generate());
Conditional Caching
$data = SmartCache::rememberIf('external_api', 3600, fn() => Http::get('https://api.example.com/data')->json(), fn($value) => !empty($value) && isset($value['status']) );
Cost-Aware Eviction
GreedyDual-Size–inspired scoring: score = (cost × ln(1 + access_count) × decay) / size
SmartCache::remember('analytics', 3600, fn() => AnalyticsService::generateReport()); SmartCache::getCacheValueReport(); // all entries ranked by value SmartCache::suggestEvictions(5); // lowest-value entries to remove
Circuit Breaker & Fallback
$data = SmartCache::withFallback( fn() => SmartCache::get('key'), fn() => $this->fallbackSource() );
In-Request Memoization
$memo = SmartCache::memo(); $users = $memo->remember('users', 3600, fn() => User::all()); $users = $memo->get('users'); // instant — served from memory
Atomic Locks
SmartCache::lock('expensive_operation', 10)->get(function () { return regenerateExpensiveData(); });
Namespacing
SmartCache::namespace('api_v2')->put('users', $users, 3600); SmartCache::flushNamespace('api_v2');
Cache Invalidation
// Pattern-based SmartCache::flushPatterns(['user_*', 'api_v2_*', '/product_\d+/']); // Dependency tracking SmartCache::dependsOn('user_posts', 'user_profile'); SmartCache::invalidate('user_profile'); // also clears user_posts // Tag-based SmartCache::tags(['users'])->put('user_1', $user, 3600); SmartCache::flushTags(['users']);
Model Auto-Invalidation
use SmartCache\Traits\CacheInvalidation; class User extends Model { use CacheInvalidation; public function getCacheKeysToInvalidate(): array { return ["user_{$this->id}_profile", "user_{$this->id}_posts", 'users_list_*']; } }
Encryption at Rest
// config/smart-cache.php → strategies.encryption 'encryption' => [ 'enabled' => true, 'keys' => ['user_token_abc123'], // exact cache-key match 'patterns' => ['/^user_token_/', '/^payment_/'], // regex match ],
Adaptive Compression
config(['smart-cache.strategies.compression.mode' => 'adaptive']); // Hot data → fast compression (level 3–4), cold data → high compression (level 7–9)
Lazy Loading
config(['smart-cache.strategies.chunking.lazy_loading' => true]); $dataset = SmartCache::get('100k_records'); // LazyChunkedCollection foreach ($dataset as $record) { /* max 3 chunks in memory */ }
Batch Operations
$values = SmartCache::many(['key1', 'key2', 'key3']); SmartCache::putMany(['key1' => $a, 'key2' => $b], 3600); SmartCache::deleteMultiple(['key1', 'key2', 'key3']);
Cache Events
config(['smart-cache.events.enabled' => true]); Event::listen(CacheHit::class, fn($e) => Log::info("Hit: {$e->key}")); Event::listen(CacheMissed::class, fn($e) => Log::warning("Miss: {$e->key}"));
Monitoring & Dashboard
SmartCache::getPerformanceMetrics(); // hit_ratio, compression_savings, timing SmartCache::analyzePerformance(); // health score + recommendations
// Enable web dashboard 'dashboard' => ['enabled' => true, 'prefix' => 'smart-cache', 'middleware' => ['web', 'auth']], // GET /smart-cache/dashboard | /smart-cache/stats | /smart-cache/health
php artisan smart-cache:status php artisan smart-cache:clear php artisan smart-cache:warm --warmer=products --warmer=categories php artisan smart-cache:cleanup-chunks
Configuration
Publish the config file (optional — sensible defaults are applied automatically):
php artisan vendor:publish --tag=smart-cache-config
// config/smart-cache.php (excerpt) return [ 'thresholds' => [ 'compression' => 1024 * 50, // 50 KB 'chunking' => 1024 * 100, // 100 KB ], 'strategies' => [ 'compression' => ['enabled' => true, 'mode' => 'fixed', 'level' => 6], 'chunking' => ['enabled' => true, 'chunk_size' => 1000], 'encryption' => ['enabled' => false, 'keys' => []], ], 'monitoring' => ['enabled' => true, 'metrics_ttl' => 3600], 'circuit_breaker' => ['enabled' => false, 'failure_threshold' => 5, 'recovery_timeout' => 30], 'rate_limiter' => ['enabled' => true, 'window' => 60, 'max_attempts' => 10], 'jitter' => ['enabled' => false, 'percentage' => 0.1], 'deduplication' => ['enabled' => true], // Write deduplication (Cache DNA) 'self_healing' => ['enabled' => true], // Auto-evict corrupted entries 'dashboard' => ['enabled' => false, 'prefix' => 'smart-cache', 'middleware' => ['web']], 'warmers' => [], // Cache warmer classes for smart-cache:warm ];
Migration from Laravel Cache
Change one import — everything else stays the same:
- use Illuminate\Support\Facades\Cache; + use SmartCache\Facades\SmartCache; SmartCache::put('users', $users, 3600); $users = SmartCache::get('users');
Documentation
Full documentation → — Installation, API reference, SWR patterns, and more.
Testing
composer test # 425 tests, 1 780+ assertions composer test-coverage # with code coverage
See TESTING.md for details.
Contributing
Please see CONTRIBUTING.md.
License
MIT — see LICENSE.