Getting Started
Illuminate\Contracts\Cache\Repository and PSR-16 SimpleCache — your existing code works unchanged.
What is SmartCache?
SmartCache wraps Laravel's caching layer with transparent optimizations while preserving full API compatibility:
📦 Intelligent Compression
Automatic gzip compression for large data — significant size reduction with zero code changes.
🧩 Smart Chunking
Breaks large arrays/objects into manageable pieces for better performance.
🔒 Atomic Locks
Prevent cache stampede and race conditions with distributed locking.
⚡ Cache Memoization
In-memory caching eliminates repeated lookups within a request or job.
🎯 Adaptive Compression
Auto-optimize compression levels based on data characteristics.
💾 Lazy Loading
On-demand chunk loading keeps memory usage low for large datasets.
📡 Cache Events
Monitor and react to cache operations in real-time.
🔄 Zero Breaking Changes
Use exactly like Laravel's Cache facade with automatic optimizations.
🧬 Write Deduplication
Skips redundant writes when content is unchanged — saves I/O for frequently refreshed data.
🩹 Self-Healing Cache
Corrupted entries are auto-evicted and transparently regenerated on the next read.
🎯 Conditional Caching
Cache only when a condition is met — filter out empty or invalid responses with rememberIf().
🔐 Encryption
Automatically encrypt sensitive cached data with pattern matching.
📁 Namespacing
Group cache keys by namespace for better organization and bulk operations.
⏱️ TTL Jitter
Prevent thundering herd with random TTL variation.
🔌 Circuit Breaker
Protect your app from cache backend failures with automatic fallbacks.
Quick Start
use SmartCache\Facades\SmartCache;
// Works exactly like Laravel Cache
SmartCache::put('users', $users, 3600);
$users = SmartCache::get('users');
Scales With Your Application
- Drop-in: Install and benefit immediately — no code changes required
- Advanced patterns: SWR, stampede protection, dependency-based invalidation
- Observability: Real-time monitoring, cost-aware eviction, performance analysis
- Enterprise-ready: Circuit breakers, encryption at rest, dashboards, HTTP management APIs
📦 Installation
Requirements
- PHP 8.1 or higher
- Laravel 8.0 - 12.x (fully tested on Laravel 8, 9, 10, 11, and 12)
- Any Laravel-supported cache driver (Redis, File, Database, Array, Memcached)
Installation Steps
composer require iazaran/smart-cache
Configuration (Optional)
SmartCache works out-of-the-box with sensible defaults. For advanced customization:
php artisan vendor:publish --tag=smart-cache-config
[
'compression' => 1024 * 50, // 50KB - compress data larger than this
'chunking' => 1024 * 100, // 100KB - chunk arrays larger than this
],
/*
|--------------------------------------------------------------------------
| Strategies
|--------------------------------------------------------------------------
|
| Configure which optimization strategies are enabled and their options.
|
*/
'strategies' => [
'compression' => [
'enabled' => true,
'level' => 6, // 0-9 (higher = better compression but slower)
],
'chunking' => [
'enabled' => true,
'chunk_size' => 1000, // Items per chunk for arrays/collections
],
],
/*
|--------------------------------------------------------------------------
| Performance Monitoring
|--------------------------------------------------------------------------
|
| Enable performance monitoring to track cache hit/miss ratios,
| optimization impact, and operation durations.
|
*/
'monitoring' => [
'enabled' => true,
'metrics_ttl' => 3600, // How long to keep metrics in cache (seconds)
'recent_entries_limit' => 100, // Number of recent operations to track
],
/*
|--------------------------------------------------------------------------
| Performance Warnings
|--------------------------------------------------------------------------
|
| Configure thresholds for performance warnings and recommendations.
|
*/
'warnings' => [
'hit_ratio_threshold' => 70, // Warn if hit ratio below this percentage
'optimization_ratio_threshold' => 20, // Warn if optimization usage below this
'slow_write_threshold' => 0.1, // Warn if writes slower than this (seconds)
],
/*
|--------------------------------------------------------------------------
| Cache Drivers
|--------------------------------------------------------------------------
|
| Configure which cache drivers should use which optimization strategies.
| Set to null to use the global strategies configuration.
|
*/
'drivers' => [
'redis' => null, // Use global settings
'file' => [
'compression' => true,
'chunking' => true,
],
'memcached' => [
'compression' => false, // Memcached has its own compression
'chunking' => true,
],
],
/*
|--------------------------------------------------------------------------
| Fallback
|--------------------------------------------------------------------------
|
| Configure fallback behavior if optimizations fail or are incompatible.
|
*/
'fallback' => [
'enabled' => true,
'log_errors' => true,
],
];
Service Provider
SmartCache automatically registers its service provider. No additional configuration is needed for Laravel 8+.
💻 Basic Usage
Familiar Laravel API
SmartCache works exactly like Laravel's built-in Cache facade. Your existing code works unchanged:
use SmartCache\Facades\SmartCache;
// Basic caching (just like Laravel Cache)
SmartCache::put('user_data', $userData, 3600);
$userData = SmartCache::get('user_data');
// Helper function (just like cache() helper)
smart_cache(['products' => $products], 3600);
$products = smart_cache('products');
// Remember pattern (just like Cache::remember)
$users = SmartCache::remember('users', 3600, function() {
return User::all();
});
// Check if key exists
if (SmartCache::has('users')) {
$users = SmartCache::get('users');
}
// Forget a key
SmartCache::forget('users');
// Clear all cache
SmartCache::flush();
Using Different Cache Drivers
Use different cache drivers while maintaining all SmartCache optimizations:
// Use Redis with all SmartCache optimizations (compression, chunking, etc.)
SmartCache::store('redis')->put('key', $value, 3600);
SmartCache::store('redis')->get('key');
// Use Memcached with optimizations
SmartCache::store('memcached')->remember('users', 3600, fn() => User::all());
// Use file cache with optimizations
SmartCache::store('file')->put('config', $config, 86400);
// Chain multiple operations on a specific store
$redisCache = SmartCache::store('redis');
$redisCache->put('users', $users, 3600);
$redisCache->put('products', $products, 3600);
// For raw access to Laravel's cache (bypasses SmartCache optimizations)
SmartCache::repository('redis')->put('key', $value, 3600);
store() method returns a SmartCache instance, so all optimization strategies (compression, chunking, encryption, etc.) continue to work. Use repository() if you need direct access to Laravel's cache without SmartCache optimizations.
Illuminate\Contracts\Cache\Repository interface, so it works seamlessly with any code that type-hints Repository. The store() method returns a SmartCache instance that is also a valid Repository, ensuring zero breaking changes when migrating from Laravel's Cache facade.
Automatic Optimization
SmartCache automatically optimizes your data when beneficial:
// Large array - automatically chunked
$largeArray = range(1, 10000);
SmartCache::put('large_data', $largeArray, 3600);
// Data is automatically chunked for better performance
// Large string - automatically compressed
$largeString = str_repeat('Hello World! ', 1000);
SmartCache::put('large_text', $largeString, 3600);
// Data is automatically compressed to save space
Cache Tags
Group related cache entries for easy management:
// Store with tags
SmartCache::tags(['users', 'profiles'])->put('user_1', $user1, 3600);
SmartCache::tags(['users', 'profiles'])->put('user_2', $user2, 3600);
// Clear all cache with specific tags
SmartCache::tags(['users'])->flush(); // Clears both user_1 and user_2
// Clear cache with multiple tags
SmartCache::tags(['users', 'profiles'])->flush();
Cache Locking
Prevent cache stampede with atomic locks:
$lock = SmartCache::lock('expensive_operation', 10);
if ($lock->get()) {
try {
// Perform expensive operation
$result = expensiveOperation();
SmartCache::put('expensive_result', $result, 3600);
} finally {
$lock->release();
}
} else {
// Wait for the lock to be released
$result = SmartCache::get('expensive_result');
}
⚡ Optimization Features
Intelligent Compression
SmartCache automatically compresses large data to reduce storage requirements:
// Large data automatically compressed
$largeData = [
'products' => Product::with('images', 'reviews')->get(),
'categories' => Category::with('children')->get(),
'settings' => Setting::all()
];
SmartCache::put('catalog_data', $largeData, 3600);
// Automatically compressed with gzip
Smart Chunking
Large arrays and objects are automatically chunked for better performance:
// Large array automatically chunked
$users = User::with('profile', 'posts')->get(); // 10,000+ records
SmartCache::put('all_users', $users, 3600);
// Automatically split into manageable chunks
Strategy Selection
SmartCache automatically chooses the best optimization strategy:
| Data Type | Size | Strategy Applied | Benefit |
|---|---|---|---|
| Large Arrays (5000+ items) | Any | Chunking | Better memory usage, faster access |
| Text/Strings | >50KB | Compression | Significant size reduction |
| Mixed Objects | >50KB | Compression | Optimal serialization |
| API Responses | >100KB | Chunking + Compression | Best performance |
| Small Data | <50KB | None | Fastest performance |
🎯 Adaptive Compression
Auto-optimize compression levels based on data characteristics:
// Enable adaptive compression
config(['smart-cache.strategies.compression.mode' => 'adaptive']);
// Automatically selects optimal compression level:
// - Hot data (frequently accessed) = level 3-4 (faster)
// - Cold data (rarely accessed) = level 7-9 (smaller)
// - Based on compressibility analysis
SmartCache::put('hot_data', $frequentlyAccessed, 3600);
SmartCache::put('cold_data', $rarelyAccessed, 3600);
💾 Lazy Loading
Load large datasets on-demand, keeping only the active chunk in memory:
// Enable lazy loading
config(['smart-cache.strategies.chunking.lazy_loading' => true]);
// Returns LazyChunkedCollection - loads chunks on-demand
$largeDataset = SmartCache::get('100k_records');
foreach ($largeDataset as $record) {
processRecord($record);
// Only 3 chunks in memory at once
}
🧠 Smart Serialization
Auto-select best serialization method:
// Automatically chooses:
// - JSON for simple arrays (fastest)
// - igbinary for complex data (if available)
// - PHP serialize as fallback
SmartCache::put('data', $value, 3600);
// Best method selected automatically
📏 Smart Chunk Sizing
Auto-calculate optimal chunk sizes based on cache driver:
// Enable smart chunk sizing
config(['smart-cache.strategies.chunking.smart_sizing' => true]);
// Automatically calculates optimal chunk size based on:
// - Cache driver limits (Redis: 512MB, Memcached: 1MB)
// - Data structure complexity
// - Serialization overhead
SmartCache::put('large_array', $data, 3600);
// Optimal chunk size calculated automatically
Configuration Options
// config/smart-cache.php
return [
'thresholds' => [
'compression' => 1024 * 50, // 50KB
'chunking' => 1024 * 100, // 100KB
],
'strategies' => [
'compression' => [
'enabled' => true,
'mode' => 'fixed', // 'fixed' or 'adaptive'
'level' => 6, // 1-9 (higher = better compression)
],
'chunking' => [
'enabled' => true,
'chunk_size' => 1000, // Items per chunk
'lazy_loading' => false, // Enable for memory savings
'smart_sizing' => false, // Auto-calculate chunk size
],
],
'events' => [
'enabled' => false, // Enable for monitoring
],
'monitoring' => [
'enabled' => true,
'metrics_ttl' => 3600,
],
];
What to Expect
🌊 SWR Patterns (Laravel 12+)
What is SWR?
SWR (Stale-While-Revalidate) is a caching strategy that serves stale data immediately while refreshing it in the background. This provides:
- ⚡ Instant responses - Users see data immediately
- 🔄 Fresh data - Background updates ensure data stays current
- 🚫 No cache stampede - Prevents multiple simultaneous requests
Basic SWR Usage
// SWR: Serve stale data while refreshing in background
$apiData = SmartCache::swr('github_repos', function() {
return Http::get('https://api.github.com/user/repos')->json();
}, 300, 900); // 5min fresh, 15min stale
Extended Stale Serving
For slowly changing data, serve stale data for extended periods:
// Extended stale serving for site configuration
$siteConfig = SmartCache::stale('site_config', function() {
return Config::fromDatabase();
}, 3600, 86400); // 1hour fresh, 24hour stale
Refresh-Ahead Caching
Proactively refresh cache before expiration:
// Refresh-ahead for expensive computations
$analytics = SmartCache::refreshAhead('daily_analytics', function() {
return Analytics::generateReport();
}, 1800, 300); // 30min TTL, 5min refresh window
Queue-Based Background Refresh
Return stale data immediately and refresh asynchronously via a queued job:
// Returns stale data instantly, dispatches a background job to refresh
$data = SmartCache::asyncSwr('dashboard_stats', function() {
return Stats::generate();
}, 300, 900, 'cache-refresh'); // 5min fresh, 15min stale, dispatched to 'cache-refresh' queue
Real-World Examples
API Gateway Cache
class ApiController
{
public function getProducts()
{
return SmartCache::swr('api_products', function() {
return Product::with('images', 'reviews')->get();
}, 300, 900); // 5min fresh, 15min stale
}
public function getUserProfile($userId)
{
return SmartCache::stale("user_profile_{$userId}", function() use ($userId) {
return User::with('profile', 'settings')->find($userId);
}, 1800, 3600); // 30min fresh, 1hour stale
}
}
E-commerce Product Recommendations
class RecommendationService
{
public function getRecommendations($userId)
{
return SmartCache::refreshAhead(
"recommendations_{$userId}",
function() use ($userId) {
return $this->aiEngine->generateRecommendations($userId);
},
3600, 600 // 1hour TTL, 10min refresh window
);
}
}
📊 Performance Monitoring
Real-Time Metrics
Get comprehensive performance metrics about your cache usage:
// Get all performance metrics
$metrics = SmartCache::getPerformanceMetrics();
/*
Returns:
[
'cache_efficiency' => [
'hit_ratio' => 0.943,
'miss_ratio' => 0.057,
'total_requests' => 1000
],
'optimization_impact' => [
'compression_savings' => 0.68,
'chunking_benefits' => 0.23,
'total_size_reduction' => 0.72
],
'operation_timing' => [
'average_get_time' => 0.023,
'average_put_time' => 0.045,
'total_operations' => 5000
]
]
*/
Health Analysis
Get automated analysis and recommendations:
// Automated performance analysis
$analysis = SmartCache::analyzePerformance();
/*
Returns:
[
'overall_health' => 'good', // good, warning, critical
'recommendations' => [
'Consider increasing cache TTL for frequently accessed data',
'Enable compression for large text data'
],
'issues' => [],
'score' => 85
]
*/
HTTP Command Execution
Manage cache via HTTP API (perfect for web-based admin panels):
// Get available commands
$commands = SmartCache::getAvailableCommands();
// Execute commands via HTTP
$status = SmartCache::executeCommand('status');
$clearResult = SmartCache::executeCommand('clear');
$specificClear = SmartCache::executeCommand('clear', [
'key' => 'expensive_computation',
'force' => true
]);
CLI Commands
# Quick status overview
php artisan smart-cache:status
# Detailed analysis with recommendations
php artisan smart-cache:status --force
# Clear all SmartCache managed keys
php artisan smart-cache:clear
# Clear specific key
php artisan smart-cache:clear expensive_api_call
# Force clear any cache key
php artisan smart-cache:clear --force
🔧 Advanced Features
🔒 Atomic Locks
Prevent multiple processes from regenerating expensive cache simultaneously (prevents race conditions):
// Prevent cache stampede with distributed locks
$lock = SmartCache::lock('expensive_operation', 10);
if ($lock->get()) {
// Only one process executes this
$data = expensiveApiCall();
SmartCache::put('api_data', $data, 3600);
$lock->release();
}
// Or use callback pattern for automatic release
SmartCache::lock('regenerate_cache', 30)->get(function() {
return regenerateExpensiveData();
});
⚡ Cache Memoization
Hold retrieved values in memory for the duration of a request or job, eliminating repeated cache lookups:
// Get memoized cache instance
$memo = SmartCache::memo();
// First call hits cache, subsequent calls are instant (from memory)
$users = $memo->remember('users', 3600, fn() => User::all());
$users = $memo->get('users'); // From memory — no cache round-trip
$users = $memo->get('users'); // Still from memory
// Perfect for loops and repeated access
foreach ($products as $product) {
$category = $memo->get("category_{$product->category_id}");
// First access hits cache, subsequent accesses are instant
}
// Get memoization statistics
$stats = $memo->getMemoizationStats();
// Returns: memoized_count, missing_count, total_memory
📡 Cache Events
Monitor and react to cache operations in real-time:
// Enable events in config
config(['smart-cache.events.enabled' => true]);
// Listen to cache operations
use SmartCache\Events\{CacheHit, CacheMissed, KeyWritten, KeyForgotten, OptimizationApplied};
Event::listen(CacheHit::class, function ($event) {
Log::info("Cache hit: {$event->key}", ['tags' => $event->tags]);
});
Event::listen(CacheMissed::class, function ($event) {
Log::warning("Cache miss: {$event->key}");
});
Event::listen(OptimizationApplied::class, function ($event) {
Log::info("Optimized {$event->key}: {$event->strategy} - {$event->ratio}% reduction");
});
🔢 Batch Operations
Optimize multiple cache operations:
// Retrieve multiple keys at once
$values = SmartCache::many(['key1', 'key2', 'key3']);
// Store multiple keys at once
SmartCache::putMany([
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3',
], 3600);
// Delete multiple keys at once
SmartCache::deleteMultiple(['key1', 'key2', 'key3']);
🎯 Adaptive Compression
Auto-optimize compression levels based on data characteristics:
// Enable adaptive compression in config
config(['smart-cache.strategies.compression.mode' => 'adaptive']);
// Automatically selects optimal compression level based on:
// - Data compressibility (sample-based analysis)
// - Access frequency (hot data = faster compression)
// - Data size (larger data = higher compression)
SmartCache::put('hot_data', $frequentlyAccessed, 3600); // Uses level 3-4 (faster)
SmartCache::put('cold_data', $rarelyAccessed, 3600); // Uses level 7-9 (smaller)
// Get compression statistics
$stats = SmartCache::getCompressionStats($optimizedValue);
// Returns: level, original_size, compressed_size, ratio, savings_bytes, savings_percent
💾 Lazy Loading
Load large datasets on-demand, keeping only the active chunk in memory:
// Enable lazy loading in config
config(['smart-cache.strategies.chunking.lazy_loading' => true]);
// Large datasets return LazyChunkedCollection
$largeDataset = SmartCache::get('100k_records');
// Chunks loaded on-demand (max 3 in memory at once)
foreach ($largeDataset as $record) {
processRecord($record);
// Only loads chunks as needed
}
// Access specific items
$item = $largeDataset[50000]; // Only loads the chunk containing this item
// Collection methods work too
$filtered = $largeDataset->filter(fn($item) => $item->active);
$mapped = $largeDataset->map(fn($item) => $item->name);
🧠 Smart Serialization
Auto-select best serialization method for optimal performance:
// Automatically chooses best method:
// - JSON for simple arrays (fastest, most compact)
// - igbinary for complex data (if available)
// - PHP serialize as fallback
SmartCache::put('simple_data', ['key' => 'value'], 3600); // Uses JSON
SmartCache::put('complex_data', $objectGraph, 3600); // Uses igbinary/PHP
// Get serialization statistics
$stats = SmartCache::getSerializationStats($optimizedValue);
// Returns: method, original_size, serialized_size, ratio
Smart Cache Invalidation
Dependency Tracking
Create cache hierarchies where invalidating a parent clears all children:
// Create cache dependencies
SmartCache::dependsOn('user_posts', 'user_profile');
SmartCache::dependsOn('user_stats', 'user_profile');
// Invalidate parent - children cleared automatically
SmartCache::invalidate('user_profile');
// This will also clear 'user_posts' and 'user_stats'
Pattern-Based Invalidation
Clear cache entries using wildcards and regex patterns:
// Pattern-based clearing
SmartCache::flushPatterns([
'user_*', // All user keys
'api_v2_*', // All API v2 cache
'/product_\d+/' // Regex: product_123, product_456
]);
Model Auto-Invalidation
Automatically clear cache when Eloquent models change:
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_*'
];
}
}
// Cache automatically cleared when user changes!
$user = User::find(1);
$user->update(['name' => 'New Name']); // Cache cleared automatically
Custom Optimization Strategies
Create custom optimization strategies for your specific needs:
use SmartCache\Contracts\OptimizationStrategy;
class JsonCompressionStrategy implements OptimizationStrategy
{
public function shouldApply(mixed $value, array $context = []): bool
{
return is_array($value) &&
json_encode($value, JSON_UNESCAPED_UNICODE) !== false &&
strlen(json_encode($value)) > 10240; // 10KB threshold
}
public function optimize(mixed $value, array $context = []): mixed
{
$json = json_encode($value, JSON_UNESCAPED_UNICODE);
return [
'_sc_json_compressed' => true,
'data' => gzcompress($json, 9)
];
}
public function restore(mixed $value, array $context = []): mixed
{
if (is_array($value) && ($value['_sc_json_compressed'] ?? false)) {
return json_decode(gzuncompress($value['data']), true);
}
return $value;
}
public function getIdentifier(): string
{
return 'json_compression';
}
}
// Register your custom strategy
SmartCache::addStrategy(new JsonCompressionStrategy());
✨ Extended Features
🔐 Encryption Strategy
Encrypt sensitive cached data automatically:
// Configure encryption in config/smart-cache.php
'encryption' => [
'enabled' => true,
'keys' => ['user_*', 'payment_*'], // Keys to encrypt
'patterns' => ['/secret_.*/'], // Regex patterns
],
// Data matching patterns is automatically encrypted
SmartCache::put('user_123_data', $sensitiveData, 3600);
// Automatically encrypted at rest
// Decryption is automatic on retrieval
$data = SmartCache::get('user_123_data');
// Returns decrypted data
📁 Cache Namespacing
Group cache keys by namespace for better organization:
// Set active namespace
SmartCache::namespace('api_v2');
// All operations now use this namespace
SmartCache::put('users', $users, 3600); // Actually stores 'api_v2:users'
SmartCache::get('users'); // Gets 'api_v2:users'
// Flush entire namespace
SmartCache::flushNamespace('api_v2');
// Get all keys in namespace
$keys = SmartCache::getNamespaceKeys('api_v2');
// Disable namespace temporarily
SmartCache::withoutNamespace()->put('global_key', $value, 3600);
⏱️ TTL Jitter
Prevent thundering herd by adding random variation to TTL:
// Enable jitter globally in config
'jitter' => [
'enabled' => true,
'percentage' => 0.1, // 10% variation
],
// Or enable per-operation
SmartCache::withJitter(0.15)->put('key', $value, 3600);
// TTL will be 3060-3540 seconds (±15%)
// Use jitter-specific methods
SmartCache::putWithJitter('key', $value, 3600, 0.2);
SmartCache::rememberWithJitter('key', 3600, fn() => $value, 0.1);
🔌 Circuit Breaker
Protect your application from cache backend failures:
// Configure circuit breaker
'circuit_breaker' => [
'enabled' => true,
'failure_threshold' => 5, // Open after 5 failures
'success_threshold' => 2, // Close after 2 successes
'timeout' => 30, // Try again after 30 seconds
],
// Check if cache is available
if (SmartCache::isAvailable()) {
$data = SmartCache::get('key');
} else {
$data = $this->fallbackSource();
}
// Use fallback automatically
$data = SmartCache::withFallback(
fn() => SmartCache::get('key'),
fn() => $this->fallbackSource()
);
// Get circuit breaker statistics
$stats = SmartCache::getCircuitBreakerStats();
// Returns: state, failures, successes, last_failure_time
🚦 Rate Limiting & Stampede Protection
Prevent cache stampede with probabilistic early expiration:
// Throttle cache regeneration
SmartCache::throttle('expensive_key', 10, 60, function() {
return expensiveOperation();
}); // Max 10 regenerations per 60 seconds
// Stampede protection with XFetch algorithm
$data = SmartCache::rememberWithStampedeProtection(
'popular_key',
3600,
fn() => expensiveQuery(),
1.0 // Beta factor (higher = earlier refresh)
);
// Configure rate limiter
'rate_limiter' => [
'enabled' => true,
'default_limit' => 100,
'window' => 60,
],
🔥 Cache Warming
Pre-populate cache with frequently accessed data:
// Create a cache warmer
use SmartCache\Contracts\CacheWarmer;
class ProductCacheWarmer implements CacheWarmer
{
public function warm(): void
{
$products = Product::with('images')->get();
SmartCache::put('all_products', $products, 3600);
}
public function getKeys(): array
{
return ['all_products'];
}
}
// Register in service provider
$this->app->tag([ProductCacheWarmer::class], 'cache.warmers');
// Run cache warming command
php artisan smart-cache:warm
// Or warm specific keys
php artisan smart-cache:warm --keys=all_products,categories
🧹 Orphan Chunk Cleanup
Automatically clean up orphaned chunks from expired data:
// Run cleanup command
php artisan smart-cache:cleanup-chunks
// Schedule automatic cleanup
// In app/Console/Kernel.php
$schedule->command('smart-cache:cleanup-chunks')->daily();
// Cleanup is also triggered automatically when:
// - A chunked key is forgotten
// - A chunked key expires and is accessed
📊 Cache Statistics Dashboard
Visual dashboard for monitoring cache performance:
// Enable dashboard in config
'dashboard' => [
'enabled' => true,
'prefix' => 'smart-cache',
'middleware' => ['web', 'auth'],
],
// Access dashboard at:
// GET /smart-cache/dashboard
// JSON API endpoints:
// GET /smart-cache/stats - Performance metrics
// GET /smart-cache/health - Health check
// GET /smart-cache/keys - Managed keys list
🔄 Background Refresh
Queue-based background cache refresh:
use SmartCache\Jobs\BackgroundCacheRefreshJob;
// Dispatch background refresh
BackgroundCacheRefreshJob::dispatch(
'expensive_key',
fn() => expensiveOperation(),
3600
);
// Or use asyncSwr — returns stale data immediately, refreshes via queue
SmartCache::asyncSwr('key', fn() => $data, 300, 900, 'cache-refresh');
🧠 Cost-Aware Caching
Inspired by the GreedyDual-Size algorithm, every remember() call automatically tracks regeneration cost, access frequency, and data size to compute a value score — letting you make data-driven eviction decisions.
score = (cost × ln(1 + access_count) × decay) / size. Expensive, frequently accessed, small entries score highest. Cheap, rarely used, large entries score lowest.
// Automatic — just use remember() as usual
$report = SmartCache::remember('analytics', 3600, function () {
return AnalyticsService::generateReport(); // 800ms callback
});
$users = SmartCache::remember('users', 3600, function () {
return User::all(); // 5ms callback
});
// See which cache entries are most valuable
$report = SmartCache::getCacheValueReport();
// [
// ['key' => 'analytics', 'cost_ms' => 800, 'access_count' => 47, 'score' => 92.4],
// ['key' => 'users', 'cost_ms' => 5, 'access_count' => 120, 'score' => 14.1],
// ]
// Get value score for a specific key
$meta = SmartCache::cacheValue('analytics');
// ['cost_ms' => 800, 'access_count' => 47, 'size_bytes' => 4096, 'score' => 92.4]
// When you need to free space, find the least valuable entries
$evictable = SmartCache::suggestEvictions(5);
// Returns the 5 lowest-score keys — safe to remove first
🧬 Write Deduplication (Cache DNA)
SmartCache hashes every value before writing. When the stored content is identical to what is already cached, the write is skipped entirely — eliminating redundant I/O for frequently refreshed but rarely changing data such as configuration, feature flags, and rate-limit counters.
// Frequent cron refreshes? Only the first write hits the store.
SmartCache::put('app_config', Config::all(), 3600);
// Second call with the same data — no I/O, returns true immediately
SmartCache::put('app_config', Config::all(), 3600);
// When data actually changes, the write proceeds normally
SmartCache::put('app_config', $updatedConfig, 3600); // written
_sc_dna:{key}. On subsequent writes, SmartCache compares the hash — if identical, the write is skipped. Hashes share the same TTL as the data and are cleaned up on forget().
// Enable/disable in config/smart-cache.php
'deduplication' => [
'enabled' => true, // enabled by default
],
🎯 Conditional Caching (rememberIf)
Cache values only when a condition is met. The callback always executes, but the result is stored only if the condition returns true. This is useful for filtering out empty, error, or invalid responses from external APIs.
// Only cache non-empty API responses
$data = SmartCache::rememberIf('external_api', 3600,
fn() => Http::get('https://api.example.com/data')->json(),
fn($value) => !empty($value) && isset($value['status'])
);
// Only cache results above a minimum size
$report = SmartCache::rememberIf('analytics_report', 7200,
fn() => AnalyticsService::generate(),
fn($result) => count($result) > 0
);
// Combined with cost-aware caching — generation cost is still tracked
$users = SmartCache::rememberIf('active_users', 1800,
fn() => User::where('active', true)->get(),
fn($users) => $users->isNotEmpty()
);
remember() with an if check, rememberIf() integrates with cost tracking and deduplication out of the box.
🩹 Self-Healing Cache
Corrupted or unrestorable cache entries are automatically evicted instead of propagating an exception to the application. Combined with remember() or rememberIf(), the entry is transparently regenerated on the next read — zero downtime, zero manual intervention.
// If 'report' is corrupted, SmartCache evicts it silently
// and the callback regenerates it on the next call
$report = SmartCache::remember('report', 3600, fn() => Analytics::generate());
// Self-healing also cleans up associated DNA hashes
// and logs the eviction for observability:
// "SmartCache self-healing: evicted corrupted key [report]"
// Enable/disable in config/smart-cache.php
'self_healing' => [
'enabled' => true, // enabled by default
],
Configuration Reference
// config/smart-cache.php
return [
// ... existing options ...
'encryption' => [
'enabled' => false,
'keys' => [],
'patterns' => [],
],
'circuit_breaker' => [
'enabled' => true,
'failure_threshold' => 5,
'success_threshold' => 2,
'timeout' => 30,
],
'rate_limiter' => [
'enabled' => true,
'default_limit' => 100,
'window' => 60,
],
'jitter' => [
'enabled' => false,
'percentage' => 0.1,
],
'cost_aware' => [
'enabled' => true, // Toggle cost tracking on/off
'max_tracked_keys' => 1000, // Limit metadata memory
'metadata_ttl' => 86400, // Metadata persistence (1 day)
],
'deduplication' => [
'enabled' => true, // Write deduplication (Cache DNA)
],
'self_healing' => [
'enabled' => true, // Auto-evict corrupted entries
],
'dashboard' => [
'enabled' => false,
'prefix' => 'smart-cache',
'middleware' => ['web'],
],
];
📚 API Reference
🔧 Basic Cache Operations
Retrieve an item from the cache with automatic restoration of optimized data.
$users = SmartCache::get('users', []);
$config = SmartCache::get('app_config', collect());
Store an item in the cache with automatic optimization (compression/chunking).
SmartCache::put('users', $users, 3600);
SmartCache::put('config', $config, now()->addHours(2));
Get an item from the cache, or execute the callback and store the result.
$users = SmartCache::remember('users', 3600, function() {
return User::with('profile')->get();
});
Get an item from the cache, or execute the callback and store the result only if the condition is met. The callback always runs on a cache miss, but the value is persisted only when $condition($value) returns true.
true to cache
$data = SmartCache::rememberIf('api_data', 3600,
fn() => Http::get('https://api.example.com/data')->json(),
fn($value) => !empty($value) && isset($value['status'])
);
Determine if an item exists in the cache.
if (SmartCache::has('users')) {
$users = SmartCache::get('users');
}
Remove an item from the cache, including any optimized chunks.
SmartCache::forget('users');
Get a SmartCache instance for a specific cache driver. All SmartCache optimizations (compression, chunking, encryption, etc.) are preserved. The returned instance also implements Illuminate\Contracts\Cache\Repository for full Laravel compatibility.
// Use Redis with all SmartCache optimizations
SmartCache::store('redis')->put('key', $value, 3600);
SmartCache::store('redis')->get('key');
// Use Memcached with optimizations
SmartCache::store('memcached')->remember('users', 3600, fn() => User::all());
// Chain operations on a specific store
$redisCache = SmartCache::store('redis');
$redisCache->put('users', $users, 3600);
$redisCache->put('products', $products, 3600);
// Works with Repository type hints
function cacheData(\Illuminate\Contracts\Cache\Repository $cache) {
$cache->put('key', 'value', 3600);
}
cacheData(SmartCache::store('redis')); // ✅ Works
Get direct access to Laravel's underlying cache repository. This bypasses all SmartCache optimizations.
// Direct access to Redis cache (no SmartCache optimizations)
SmartCache::repository('redis')->put('key', $value, 3600);
// Direct access to default cache store
SmartCache::repository()->get('key');
repository() only when you need to bypass SmartCache optimizations. For normal usage, prefer store() to maintain all optimization benefits.
🌊 SWR Patterns (Laravel 12+)
Stale-While-Revalidate pattern - serves stale data while refreshing in background.
$apiData = SmartCache::swr('github_repos', function() {
return Http::get('https://api.github.com/user/repos')->json();
}, 300, 900); // 5min fresh, 15min stale
Extended stale serving - allows serving stale data for extended periods.
$siteConfig = SmartCache::stale('site_config', function() {
return Config::fromDatabase();
}, 3600, 86400); // 1hour fresh, 24hour stale
Refresh-ahead pattern - proactively refreshes cache before expiration.
$analytics = SmartCache::refreshAhead('daily_analytics', function() {
return Analytics::generateReport();
}, 1800, 300); // 30min TTL, 5min refresh window
Queue-based background SWR — returns stale data immediately and dispatches a queued job to refresh the cache asynchronously.
$data = SmartCache::asyncSwr('dashboard_stats', function() {
return Stats::generate();
}, 300, 900, 'cache-refresh'); // 5min fresh, 15min stale, queued on 'cache-refresh'
🔗 Cache Invalidation & Dependencies
Tag cache entries for organized invalidation.
SmartCache::tags(['users', 'profiles'])->put('user_1', $user1, 3600);
SmartCache::tags('products')->put('product_123', $product, 1800);
Flush all cache entries associated with given tags.
SmartCache::flushTags(['users']); // Clear all user-related cache
Add cache key dependency relationships.
SmartCache::dependsOn('user_posts', 'user_profile');
Clear cache entries matching wildcard or regex patterns.
$cleared = SmartCache::flushPatterns([
'user_*', // All user keys
'api_v2_*', // All API v2 cache
'/product_\d+/' // Regex: product_123, product_456
]);
📊 Performance Monitoring
Get comprehensive performance metrics about cache usage.
$metrics = SmartCache::getPerformanceMetrics();
/*
Returns:
[
'cache_efficiency' => [
'hit_ratio' => 0.943,
'miss_ratio' => 0.057,
'total_requests' => 1000
],
'optimization_impact' => [
'compression_savings' => 0.68,
'chunking_benefits' => 0.23,
'total_size_reduction' => 0.72
]
]
*/
Get automated performance analysis and recommendations.
$analysis = SmartCache::analyzePerformance();
/*
Returns:
[
'overall_health' => 'good', // good, warning, critical
'recommendations' => [
'Consider increasing cache TTL for frequently accessed data'
],
'score' => 85
]
*/
Execute cache management commands programmatically.
$status = SmartCache::executeCommand('status');
$result = SmartCache::executeCommand('clear', ['key' => 'specific_key']);
🔧 Extended API
Get a lock instance to prevent cache stampede and race conditions.
$lock = SmartCache::lock('expensive_operation', 10);
if ($lock->get()) {
$data = expensiveApiCall();
SmartCache::put('api_data', $data, 3600);
$lock->release();
}
Get a memoized cache instance that holds values in memory for the current request.
$memo = SmartCache::memo();
$users = $memo->remember('users', 3600, fn() => User::all());
$users = $memo->get('users'); // From memory — no cache round-trip
Retrieve multiple cache keys at once.
$values = SmartCache::many(['key1', 'key2', 'key3']);
Store multiple cache keys at once.
SmartCache::putMany([
'key1' => 'value1',
'key2' => 'value2',
], 3600);
Delete multiple cache keys at once.
SmartCache::deleteMultiple(['key1', 'key2', 'key3']);
Get compression statistics for optimized data.
$optimized = SmartCache::optimize($data);
$stats = SmartCache::getCompressionStats($optimized);
// Returns: level, original_size, compressed_size, ratio, savings_bytes, savings_percent
Get serialization statistics for optimized data.
$optimized = SmartCache::optimize($data);
$stats = SmartCache::getSerializationStats($optimized);
// Returns: method, original_size, serialized_size, ratio
✨ Resilience & Organization API
Set the active namespace for cache operations.
SmartCache::namespace('api_v2')->put('users', $users, 3600);
// Stores as 'api_v2:users'
Flush all cache entries in a namespace.
$count = SmartCache::flushNamespace('api_v2');
// Clears all keys prefixed with 'api_v2:'
Enable TTL jitter for subsequent operations.
SmartCache::withJitter(0.15)->put('key', $value, 3600);
// TTL will be 3060-3540 seconds (±15%)
Check if cache backend is available (circuit breaker).
if (SmartCache::isAvailable()) {
$data = SmartCache::get('key');
} else {
$data = $this->fallbackSource();
}
Execute cache operation with automatic fallback on failure.
$data = SmartCache::withFallback(
fn() => SmartCache::get('key'),
fn() => $this->database->get('key')
);
Rate-limit cache regeneration to prevent stampede.
$data = SmartCache::throttle('expensive_key', 10, 60, function() {
return expensiveOperation();
}); // Max 10 regenerations per 60 seconds
Remember with XFetch algorithm for probabilistic early refresh.
$data = SmartCache::rememberWithStampedeProtection(
'popular_key', 3600, fn() => expensiveQuery(), 1.0
);
Get circuit breaker statistics.
$stats = SmartCache::getCircuitBreakerStats();
// Returns: ['state' => 'closed', 'failures' => 0, 'successes' => 5]
🧠 Cost-Aware Caching API
Get value score metadata for a specific cache key.
$meta = SmartCache::cacheValue('analytics');
// ['cost_ms' => 800, 'access_count' => 47, 'size_bytes' => 4096, 'score' => 92.4, ...]
Get a full report of all tracked cache entries sorted by value score (highest first).
$report = SmartCache::getCacheValueReport();
// [
// ['key' => 'analytics', 'cost_ms' => 800, 'access_count' => 47, 'score' => 92.4],
// ['key' => 'users', 'cost_ms' => 5, 'access_count' => 120, 'score' => 14.1],
// ]
Suggest the lowest-value cache entries for eviction when you need to free space.
$evictable = SmartCache::suggestEvictions(5);
// Returns the 5 lowest-score keys — safest to remove first
foreach ($evictable as $entry) {
SmartCache::forget($entry['key']);
}
Get the underlying CostAwareCacheManager instance for advanced usage.
$manager = SmartCache::getCostAwareManager();
if ($manager) {
echo "Tracking " . $manager->trackedKeyCount() . " keys";
}
🛠️ Cache Management
Clear all cache keys managed by SmartCache (tracked keys only).
SmartCache::clear(); // Clear all SmartCache managed keys
Flush the entire cache store (all keys, not just SmartCache-managed ones). Equivalent to Laravel's Cache::flush().
SmartCache::flush(); // Flush ALL cache keys (entire store)
Get the raw (unrestored) value from cache, bypassing optimization strategies. Useful for diagnostics and debugging.
$raw = SmartCache::getRaw('users');
// Returns the raw stored value with compression/chunking markers intact
Get all keys currently managed by SmartCache.
$keys = SmartCache::getManagedKeys();
foreach ($keys as $key) {
echo "Managed key: {$key}\n";
}
🔧 Helper Functions
Global helper function for SmartCache operations.
// Get SmartCache instance
$cache = smart_cache();
// Get value
$users = smart_cache('users');
// Set value
smart_cache('users', $users, 3600);
💻 CLI Commands
Display comprehensive information about SmartCache usage, configuration, and performance.
# Basic status overview
php artisan smart-cache:status
# Detailed analysis with recommendations
php artisan smart-cache:status --force
Clear SmartCache managed items. Optionally specify a key to clear only that item.
# Clear all SmartCache managed keys
php artisan smart-cache:clear
# Clear specific key
php artisan smart-cache:clear user_profile_123
# Force clear any cache key
php artisan smart-cache:clear --force
Pre-populate cache with frequently accessed data using registered warmers.
# Warm all registered cache warmers
php artisan smart-cache:warm
# Warm specific keys only
php artisan smart-cache:warm --keys=products,categories
Clean up orphaned chunks from expired or deleted chunked cache entries.
# Run cleanup manually
php artisan smart-cache:cleanup-chunks
# Schedule in Kernel.php
$schedule->command('smart-cache:cleanup-chunks')->daily();
🧪 Testing & Validation
Test Controller
The controller below exercises core SmartCache features — basic operations, compression, chunking, SWR patterns, invalidation, and monitoring — and returns structured JSON results.
Controller Implementation
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use SmartCache\Facades\SmartCache;
class TestSmartCacheDirectlyController extends Controller
{
public function testSmartCacheFeatures()
{
$packageInfo = ['version' => '1.4.2', 'features_tested' => 20];
$tests = [];
try {
// Test 1: Basic Operations
$tests['basic_operations'] = $this->testBasicOperations();
// Test 2: Compression (2000+ records)
$tests['compression_test'] = $this->testCompressionFeature();
// Test 3: Chunking (5000+ items)
$tests['chunking_test'] = $this->testChunkingFeature();
// Test 4: Helper Functions
$tests['helper_function'] = $this->testHelperFunctions();
// Test 5: SWR Patterns (Laravel 12+)
if (version_compare(app()->version(), '12.0', '>=')) {
$tests['swr_patterns'] = $this->testSWRPatterns();
}
// Test 6: Cache Invalidation & Tags
$tests['cache_invalidation'] = $this->testCacheInvalidation();
// Test 7: Performance Monitoring
$tests['performance_monitoring'] = $this->testPerformanceMonitoring();
// Test 8: Advanced Features (remember, locking)
$tests['advanced_features'] = $this->testAdvancedFeatures();
return response()->json([
'message' => 'SmartCache feature tests completed',
'package_info' => $packageInfo,
'tests' => $tests,
'overall_status' => 'success'
]);
} catch (\Exception $e) {
return response()->json([
'message' => 'SmartCache test failed',
'error' => $e->getMessage()
], 500);
}
}
private function testBasicOperations()
{
$testData = ['data' => 'test_value', 'number' => 123, 'array' => range(1, 10)];
// Test facade operations
SmartCache::put('test_facade', $testData, 300);
$facadeResult = SmartCache::get('test_facade');
// Test helper operations
smart_cache(['test_helper' => $testData], 300);
$helperResult = smart_cache('test_helper');
return [
'status' => 'success',
'facade_results' => [
'data_integrity' => $testData === $facadeResult,
'has_key' => SmartCache::has('test_facade')
],
'helper_results' => [
'data_integrity' => $testData === $helperResult,
'has_key' => SmartCache::has('test_helper')
],
'both_methods_working' => ($testData === $facadeResult && $testData === $helperResult)
];
}
// ... Additional test methods for compression, chunking, SWR patterns, etc.
// See complete implementation in the GitHub Gist
}
How to Use the Test Controller
1. Installation
Add this controller to your Laravel application:
php artisan make:controller Api/V1/TestSmartCacheDirectlyController
Route::get('/test-smart-cache', [TestSmartCacheDirectlyController::class, 'testSmartCacheFeatures']);
2. Running the Tests
Access the endpoint to run comprehensive tests:
# Via HTTP request
curl http://your-app.com/api/test-smart-cache
# Or via browser
http://your-app.com/api/test-smart-cache
3. Understanding the Results
The test controller returns a comprehensive JSON response with detailed results:
{
"message": "SmartCache feature tests completed",
"package_info": {
"version": "1.4.2",
"features_tested": 20
},
"tests": {
"basic_operations": {
"status": "success",
"both_methods_working": true,
"facade_results": { "data_integrity": true, "has_key": true },
"helper_results": { "data_integrity": true, "has_key": true }
},
"compression_test": {
"status": "success",
"original_count": 2000,
"estimated_size_kb": 2207.29,
"both_methods_successful": true
},
"chunking_test": {
"status": "success",
"original_count": 5000,
"data_matches": true
},
"performance_monitoring": {
"status": "success",
"monitoring_working": true
}
// ... additional test results
},
"overall_status": "success"
}
What Each Test Validates
🔧 Basic Operations
Tests put/get/has/forget operations with both facade and helper functions, ensuring data integrity and method compatibility.
📦 Compression Testing
Validates automatic compression with 2000+ records, measuring size reduction and performance impact.
🧩 Chunking Validation
Tests chunking strategy with 5000+ items, verifying data integrity and retrieval performance.
🌊 SWR Patterns
Validates Stale-While-Revalidate patterns, write-through, write-behind, and cache-aside strategies.
🔗 Cache Invalidation
Tests tag-based invalidation, pattern matching, and dependency tracking features.
📊 Performance Monitoring
Validates metrics collection, performance analysis, and automated recommendations.
Full controller source: GitHub Gist
🔄 Migration Guide
From Laravel Cache
SmartCache implements the same Repository contract as Laravel's Cache facade. Migration requires one import change:
composer require iazaran/smart-cache
// Before
use Illuminate\Support\Facades\Cache;
// After
use SmartCache\Facades\SmartCache;
// Before
Cache::put('key', $value, 3600);
$value = Cache::get('key');
// SmartCache (works exactly the same, with automatic optimizations)
SmartCache::put('key', $value, 3600);
$value = SmartCache::get('key');
Gradual Migration
You can migrate gradually by using both facades:
use Illuminate\Support\Facades\Cache;
use SmartCache\Facades\SmartCache;
// Keep existing code unchanged
Cache::put('old_key', $value, 3600);
// Use SmartCache for optimized caching
SmartCache::put('optimized_key', $value, 3600);
SmartCache::swr('api_data', $callback, 300, 900);
Testing Migration
Test your migration with these commands:
# Test basic functionality
php artisan smart-cache:status
# Test with your application
php artisan tinker
>>> SmartCache::put('test', 'Hello World', 60);
>>> SmartCache::get('test');
=> "Hello World"
Rollback Plan
If you need to rollback, simply change the imports back:
# Change back to Laravel Cache imports in your code
# Then remove SmartCache package
composer remove iazaran/smart-cache