Caching API

High-performance caching system with multiple drivers, cache tagging, and advanced features. The caching system provides a unified interface for various storage backends including Redis, Memcached, file-based, and database caching with support for cache tags, TTL, and atomic operations.

Cache Manager

Central cache management class that provides a unified interface for all caching operations. The CacheManager handles driver initialization, configuration management, and provides factory methods for creating cache instances.

Basic Cache Operations

Cache Configuration

Configure cache drivers and settings.

use Forge\Cache\CacheManager;
use Forge\Cache\Drivers\RedisDriver;
use Forge\Cache\Drivers\FileDriver;
use Forge\Cache\Drivers\DatabaseDriver;

// Create cache manager
$cacheManager = new CacheManager();

// Configure default cache store
$cacheManager->setDefaultStore('redis');

// Configure cache stores
$cacheManager->setStores([
    'redis' => [
        'driver' => RedisDriver::class,
        'connection' => 'default',
        'prefix' => 'forge_cache:',
        'ttl' => 3600
    ],
    'file' => [
        'driver' => FileDriver::class,
        'path' => storage_path('framework/cache'),
        'prefix' => 'forge_',
        'ttl' => 7200
    ],
    'database' => [
        'driver' => DatabaseDriver::class,
        'table' => 'cache',
        'connection' => 'default',
        'prefix' => 'forge_',
        'ttl' => 86400
    ],
    'array' => [
        'driver' => 'array',
        'ttl' => 300
    ]
]);

// Get cache instance
$cache = $cacheManager->store('redis');
$defaultCache = $cacheManager->store(); // Uses default store

// Configure global settings
$cacheManager->setConfig([
    'prefix' => 'app_',
    'ttl' => 3600,
    'serialize' => true,
    'compression' => true,
    'encryption' => false
]);

Basic Cache Operations

Store, retrieve, and delete cache items.

// Store data in cache
$cache->put('user:1', $userData, 3600); // TTL in seconds
$cache->put('settings', $settings, now()->addHours(2));

// Store if not exists
$cache->add('counter', 1, 300); // Returns true if added, false if exists

// Retrieve data from cache
$user = $cache->get('user:1');
$settings = $cache->get('settings', function() {
    // This callback is executed if key doesn't exist
    return $this->loadSettingsFromDatabase();
});

// Check if key exists
if ($cache->has('user:1')) {
    $user = $cache->get('user:1');
}

// Delete cache items
$cache->forget('user:1');
$cache->delete('settings');

// Delete multiple keys
$cache->deleteMultiple(['user:1', 'user:2', 'user:3']);

// Clear all cache
$cache->flush();

// Get and delete (pull)
$user = $cache->pull('user:1'); // Gets and removes from cache

// Increment/decrement
$cache->increment('visits');
$cache->increment('visits', 5);
$cache->decrement('stock');
$cache->decrement('stock', 2);

// Remember pattern
$users = $cache->remember('users.active', 3600, function() {
    return User::where('active', true)->get();
});

// Remember forever
$countries = $cache->rememberForever('countries', function() {
    return Country::all();
});

Advanced Cache Features

Cache Tags

Organize and manage related cache items using tags.

// Store with tags
$cache->tags(['users', 'profiles'])->put('user:1', $userData, 3600);
$cache->tags(['posts', 'recent'])->put('posts.recent', $recentPosts, 1800);

// Retrieve with tags
$user = $cache->tags(['users'])->get('user:1');
$posts = $cache->tags(['posts', 'recent'])->get('posts.recent');

// Flush specific tags
$cache->tags(['users'])->flush(); // Remove all items tagged with 'users'
$cache->tags(['posts', 'recent'])->flush(); // Remove items with both tags

// Multiple tags operations
$cache->tags(['users', 'admins'])->put('admin:1', $adminData, 3600);

// Get all keys for a tag
$userKeys = $cache->tags(['users'])->getKeys();

// Check if tagged item exists
if ($cache->tags(['users'])->has('user:1')) {
    // Process cached user data
}

// Tagged remember pattern
$admins = $cache->tags(['users', 'admins'])->remember('admins.all', 3600, function() {
    return User::where('role', 'admin')->get();
});

// Clear cache by tags (useful for cache invalidation)
$cache->tags(['user:1', 'posts'])->flush(); // Clear user's posts
$cache->tags(['category:tech'])->flush(); // Clear tech category cache

Cache Locking

Prevent cache stampedes with atomic locking.

// Acquire lock
$lock = $cache->lock('expensive-operation', 30); // 30 second timeout

if ($lock->get()) {
    try {
        // Perform expensive operation
        $data = $this->performExpensiveOperation();
        
        // Cache the result
        $cache->put('expensive-data', $data, 3600);
        
        return $data;
    } finally {
        $lock->release();
    }
}

// Wait for lock with timeout
$lock = $cache->lock('report-generation', 60);

if ($lock->block(10)) { // Wait up to 10 seconds
    try {
        // Generate report
        $report = $this->generateReport();
        
        // Cache result
        $cache->put('report:latest', $report, 3600);
        
        return $report;
    } finally {
        $lock->release();
    }
} else {
    throw new \Exception('Could not acquire lock for report generation');
}

// Scoped locks
$cache->lock('user:1:update', 30)->get(function() use ($cache, $userId) {
    // This code is executed atomically
    $user = $cache->get('user:1');
    $user['last_seen'] = now();
    $cache->put('user:1', $user, 3600);
});

// Check if lock exists
if ($cache->lock('maintenance')->exists()) {
    echo "Maintenance in progress";
}

// Force release lock
$cache->lock('stuck-operation')->forceRelease();

Cache Drivers

Different storage backends for caching with specific features and configurations. Each driver provides optimized performance for different use cases and environments.

Redis Driver

Redis Cache Configuration

High-performance Redis-based caching with advanced features.

use Forge\Cache\Drivers\RedisDriver;
use Forge\Redis\RedisManager;

// Configure Redis driver
$redisDriver = new RedisDriver([
    'connection' => 'cache',
    'prefix' => 'forge_cache:',
    'serializer' => 'json', // json, php, igbinary, msgpack
    'compression' => true,
    'ttl' => 3600
]);

// Advanced Redis configuration
$redisDriver->setRedis(new RedisManager([
    'scheme' => 'tcp',
    'host' => '127.0.0.1',
    'port' => 6379,
    'password' => null,
    'database' => 1,
    'timeout' => 5.0,
    'read_timeout' => 10.0,
    'persistent' => true,
    'prefix' => 'forge:',
    'serializer' => Redis::SERIALIZER_JSON,
    'compression' => Redis::COMPRESSION_LZ4,
    'retry_interval' => 100,
    'retry_timeout' => 2000
]));

// Redis-specific operations
$redisDriver->set('user:1', $userData, 3600);

// Use Redis data structures
$redisDriver->lpush('recent_users', 'user:1');
$redisDriver->ltrim('recent_users', 0, 99); // Keep last 100

$redisDriver->sadd('online_users', 'user:1');
$redisDriver->srem('online_users', 'user:2');

$redisDriver->zadd('leaderboard', 100, 'user:1');
$redisDriver->zincrby('leaderboard', 10, 'user:1');

// Hash operations
$redisDriver->hset('user:1:session', 'last_seen', time());
$redisDriver->hget('user:1:session', 'last_seen');
$redisDriver->hgetall('user:1:session');

// Set expiration
$redisDriver->expire('temp_key', 300); // 5 minutes
$redisDriver->expireat('temp_key', strtotime('+1 hour'));

// Check TTL
$ttl = $redisDriver->ttl('user:1'); // Returns seconds remaining

// Persistence control
$redisDriver->save(); // Synchronous save
$redisDriver->bgsave(); // Background save

// Pipeline operations for bulk processing
$redisDriver->pipeline(function($pipe) {
    for ($i = 0; $i < 1000; $i++) {
        $pipe->set("key:{$i}", "value:{$i}", 3600);
    }
});

Redis Cluster Configuration

Configure Redis cluster for high availability.

$redisDriver->setRedis(new RedisManager([
    'cluster' => true,
    'clusters' => [
        'default' => [
            ['host' => '127.0.0.1', 'port' => 7000],
            ['host' => '127.0.0.1', 'port' => 7001],
            ['host' => '127.0.0.1', 'port' => 7002],
        ],
        'cache' => [
            ['host' => '127.0.0.1', 'port' => 7003],
            ['host' => '127.0.0.1', 'port' => 7004],
            ['host' => '127.0.0.1', 'port' => 7005],
        ]
    ],
    'options' => [
        'timeout' => 5.0,
        'read_timeout' => 10.0,
        'persistent' => true,
        'failover' => 'error', // error, distribute, none
        'slave_failover' => 'distribute'
    ]
]));

// Redis Sentinel configuration
$redisDriver->setRedis(new RedisManager([
    'sentinel' => true,
    'sentinels' => [
        ['host' => 'sentinel1', 'port' => 26379],
        ['host' => 'sentinel2', 'port' => 26379],
        ['host' => 'sentinel3', 'port' => 26379]
    ],
    'service' => 'mymaster',
    'password' => 'redis_password',
    'database' => 0
]));

File Driver

File Cache Configuration

File-based caching with directory organization.

use Forge\Cache\Drivers\FileCacheDriver;

// Configure file driver
$fileDriver = new FileCacheDriver([
    'path' => storage_path('framework/cache'),
    'prefix' => 'forge_',
    'permission' => 0644,
    'directory_permission' => 0755,
    'ttl' => 7200,
    'serialize' => true,
    'compression' => false,
    'encryption' => false
]);

// Advanced file cache configuration
$fileDriver->setConfig([
    'path' => storage_path('framework/cache/data'),
    'hash_directory' => true, // Use hash-based directory structure
    'directory_level' => 2, // Number of directory levels
    'file_extension' => '.cache',
    'max_file_size' => 1048576, // 1MB max file size
    'gc_probability' => 0.01, // 1% garbage collection chance
    'gc_divisor' => 100,
    'lock_file' => true, // Use file locking
    'lock_timeout' => 30 // 30 seconds
]);

// Organize cache by directories
$fileDriver->put('config/app', $appConfig, 3600);
$fileDriver->put('config/database', $dbConfig, 3600);
$fileDriver->put('views/home', $homeView, 1800);
$fileDriver->put('data/users', $userData, 3600);

// Use different storage paths
$fileDriver->setPath(storage_path('framework/cache/views'));
$fileDriver->put('template:main', $templateData, 86400);

$fileDriver->setPath(storage_path('framework/cache/sessions'));
$fileDriver->put('session:' . $sessionId, $sessionData, 1800);

// File-specific operations
$fileDriver->clean(); // Remove expired files
$fileDriver->gc(); // Run garbage collection
$fileDriver->optimize(); // Optimize storage structure

// Get cache statistics
$stats = $fileDriver->getStats();
echo "Total files: " . $stats['files'];
echo "Total size: " . $stats['size'];
echo "Expired files: " . $stats['expired'];

// Backup cache files
$fileDriver->backup(storage_path('backups/cache-' . date('Y-m-d') . '.tar.gz'));

// Restore cache files
$fileDriver->restore(storage_path('backups/cache-2024-01-01.tar.gz'));

Database Driver

Database Cache Configuration

Database-based caching with automatic table management.

use Forge\Cache\Drivers\DatabaseCacheDriver;

// Configure database driver
$dbDriver = new DatabaseCacheDriver([
    'table' => 'cache',
    'connection' => 'default',
    'prefix' => 'forge_',
    'ttl' => 86400,
    'serialize' => true,
    'compression' => true,
    'encryption' => false,
    'chunk_size' => 1000
]);

// Database cache table schema
$schema = "
CREATE TABLE cache (
    key VARCHAR(255) PRIMARY KEY,
    value TEXT NOT NULL,
    expiration INT NOT NULL,
    tags TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_expiration (expiration),
    INDEX idx_tags (tags(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
";

// Advanced database cache configuration
$dbDriver->setConfig([
    'table' => 'cache',
    'connection' => 'cache',
    'chunk_size' => 500,
    'batch_size' => 50,
    'cleanup_batch_size' => 100,
    'gc_frequency' => 0.1, // 10% chance of cleanup
    'index_tags' => true,
    'index_expiration' => true,
    'partition_by_date' => false,
    'archive_old' => true,
    'archive_table' => 'cache_archive'
]);

// Database-specific operations
$dbDriver->clean(); // Remove expired entries
$dbDriver->vacuum(); // Optimize table
$dbDriver->analyze(); // Update statistics

// Batch operations
$dbDriver->putMany([
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3'
], 3600);

$values = $dbDriver->getMany(['key1', 'key2', 'key3']);

// Tagged database cache
$dbDriver->tags(['users', 'recent'])->put('users.recent', $users, 3600);

// Database cache statistics
$stats = $dbDriver->getStats();
echo "Total entries: " . $stats['total'];
echo "Expired entries: " . $stats['expired'];
echo "Average size: " . $stats['avg_size'];

// Cleanup operations
$deleted = $dbDriver->cleanup(); // Remove expired entries
$optimized = $dbDriver->optimize(); // Optimize storage

Cache Patterns

Common caching patterns and strategies for different use cases. These patterns help implement efficient caching strategies for various application scenarios.

Cache-Aside Pattern

Manual Cache Management

Application manages cache explicitly.

class UserRepository
{
    private $cache;
    
    public function __construct(CacheManager $cache)
    {
        $this->cache = $cache;
    }
    
    public function find($id)
    {
        $key = "user:{$id}";
        
        // Try to get from cache
        $user = $this->cache->get($key);
        
        if ($user === null) {
            // Not in cache, get from database
            $user = User::find($id);
            
            if ($user) {
                // Store in cache
                $this->cache->put($key, $user, 3600);
                $this->cache->tags(['users', "user:{$id}"])->put($key, $user, 3600);
            }
        }
        
        return $user;
    }
    
    public function update($id, array $data)
    {
        $user = User::find($id);
        
        if ($user) {
            $user->update($data);
            
            // Update cache
            $this->cache->put("user:{$id}", $user, 3600);
            
            // Invalidate related caches
            $this->cache->tags(['users'])->flush();
            $this->cache->tags(['user:{$id}'])->flush();
        }
        
        return $user;
    }
    
    public function delete($id)
    {
        User::destroy($id);
        
        // Remove from cache
        $this->cache->forget("user:{$id}");
        
        // Invalidate related caches
        $this->cache->tags(['users'])->flush();
        $this->cache->tags(['user:{$id}'])->flush();
    }
}

Write-Through Pattern

Automatic Cache Updates

Cache is updated automatically on data changes.

class CachedUserRepository
{
    private $cache;
    
    public function __construct(CacheManager $cache)
    {
        $this->cache = $cache;
    }
    
    public function create(array $data)
    {
        // Create user in database
        $user = User::create($data);
        
        // Automatically cache the new user
        $this->cache->tags(['users', "user:{$user->id}"])->put(
            "user:{$user->id}",
            $user,
            3600
        );
        
        // Invalidate user lists
        $this->cache->tags(['user_lists'])->flush();
        
        return $user;
    }
    
    public function update($id, array $data)
    {
        // Update user in database
        $user = User::find($id);
        
        if ($user) {
            $user->update($data);
            
            // Update cache immediately
            $this->cache->tags(['users', "user:{$id}"])->put(
                "user:{$id}",
                $user,
                3600
            );
            
            // Invalidate related caches
            $this->cache->tags(['user_lists', 'user:{$id}:related'])->flush();
        }
        
        return $user;
    }
    
    public function getAll($page = 1, $perPage = 20)
    {
        $key = "users:page:{$page}:per_page:{$perPage}";
        
        return $this->cache->tags(['user_lists'])->remember($key, 1800, function() use ($page, $perPage) {
            return User::paginate($perPage, ['*'], 'page', $page);
        });
    }
}

Cache Warming

Proactive Cache Population

Pre-populate cache with frequently accessed data.

class CacheWarmer
{
    private $cache;
    
    public function __construct(CacheManager $cache)
    {
        $this->cache = $cache;
    }
    
    public function warmCache()
    {
        // Warm user data
        $this->warmUsers();
        
        // Warm configuration
        $this->warmConfiguration();
        
        // Warm frequently accessed data
        $this->warmFrequentlyAccessedData();
        
        // Warm reference data
        $this->warmReferenceData();
    }
    
    private function warmUsers()
    {
        // Cache active users
        $activeUsers = User::where('active', true)
            ->limit(1000)
            ->get();
            
        foreach ($activeUsers as $user) {
            $this->cache->tags(['users', "user:{$user->id}"])->put(
                "user:{$user->id}",
                $user,
                3600
            );
        }
        
        // Cache user lists
        $this->cache->tags(['user_lists'])->remember('users.active', 3600, function() {
            return User::where('active', true)->get();
        });
        
        $this->cache->tags(['user_lists'])->remember('users.recent', 1800, function() {
            return User::orderBy('created_at', 'desc')
                ->limit(100)
                ->get();
        });
    }
    
    private function warmConfiguration()
    {
        // Cache application configuration
        $config = [
            'app_name' => config('app.name'),
            'app_debug' => config('app.debug'),
            'app_url' => config('app.url'),
            'mail_driver' => config('mail.driver'),
            'cache_default' => config('cache.default'),
            'session_driver' => config('session.driver')
        ];
        
        $this->cache->tags(['config'])->put('app.config', $config, 86400);
    }
    
    private function warmFrequentlyAccessedData()
    {
        // Cache dashboard statistics
        $this->cache->tags(['dashboard'])->remember('stats.users', 3600, function() {
            return [
                'total' => User::count(),
                'active' => User::where('active', true)->count(),
                'today' => User::whereDate('created_at', today())->count(),
                'this_month' => User::whereMonth('created_at', now()->month)->count()
            ];
        });
        
        // Cache recent posts
        $this->cache->tags(['posts'])->remember('posts.recent', 1800, function() {
            return Post::with('author')
                ->where('published', true)
                ->orderBy('created_at', 'desc')
                ->limit(50)
                ->get();
        });
        
        // Cache popular content
        $this->cache->tags(['content'])->remember('content.popular', 3600, function() {
            return Post::where('published', true)
                ->orderBy('views', 'desc')
                ->limit(20)
                ->get();
        });
    }
    
    private function warmReferenceData()
    {
        // Cache countries
        $this->cache->tags(['reference'])->rememberForever('countries', function() {
            return Country::all();
        });
        
        // Cache categories
        $this->cache->tags(['reference'])->rememberForever('categories', function() {
            return Category::all();
        });
        
        // Cache settings
        $this->cache->tags(['settings'])->rememberForever('settings', function() {
            return Setting::pluck('value', 'key');
        });
    }
    
    // Schedule cache warming
    public function scheduleWarming()
    {
        // Warm cache every hour
        schedule()->call(function() {
            $this->warmCache();
        })->hourly();
        
        // Warm critical data every 15 minutes
        schedule()->call(function() {
            $this->warmFrequentlyAccessedData();
        })->everyFifteenMinutes();
        
        // Warm reference data daily
        schedule()->call(function() {
            $this->warmReferenceData();
        })->daily();
    }
}

Cache Performance

Monitor and optimize cache performance with metrics, profiling, and tuning. Understanding cache performance helps identify bottlenecks and optimization opportunities.

Performance Monitoring

Cache Metrics

Monitor cache performance and usage.

use Forge\Cache\CacheProfiler;
use Forge\Cache\CacheMetrics;

// Enable profiling
$profiler = new CacheProfiler($cacheManager);
$profiler->enable();

// Get cache metrics
$metrics = new CacheMetrics($cacheManager);

// Hit/miss ratio
$hitRate = $metrics->getHitRate(); // 0.95 (95%)
$missRate = $metrics->getMissRate(); // 0.05 (5%)

// Operation counts
$stats = $metrics->getStats();
echo "Gets: " . $stats['gets'];
echo "Sets: " . $stats['sets'];
echo "Deletes: " . $stats['deletes'];
echo "Hits: " . $stats['hits'];
echo "Misses: " . $stats['misses'];

// Memory usage
$memoryUsage = $metrics->getMemoryUsage();
echo "Used memory: " . $memoryUsage['used'];
echo "Free memory: " . $memoryUsage['free'];
echo "Total memory: " . $memoryUsage['total'];

// Performance metrics
$performance = $metrics->getPerformance();
echo "Average get time: " . $performance['avg_get_time'] . "ms";
echo "Average set time: " . $performance['avg_set_time'] . "ms";
echo "Average delete time: " . $performance['avg_delete_time'] . "ms";

// Top cached keys
$topKeys = $metrics->getTopKeys(10);
foreach ($topKeys as $key => $hits) {
    echo "{$key}: {$hits} hits";
}

// Least used keys
$leastUsed = $metrics->getLeastUsedKeys(10);

// Cache efficiency
$efficiency = $metrics->getEfficiency();
echo "Cache efficiency: " . ($efficiency * 100) . "%";

// Store metrics for analysis
$metrics->recordMetrics([
    'timestamp' => time(),
    'hit_rate' => $hitRate,
    'memory_usage' => $memoryUsage,
    'performance' => $performance
]);

Performance Optimization

Optimize cache performance based on metrics.

class CacheOptimizer
{
    private $cache;
    private $metrics;
    
    public function __construct(CacheManager $cache, CacheMetrics $metrics)
    {
        $this->cache = $cache;
        $this->metrics = $metrics;
    }
    
    public function optimize()
    {
        // Analyze current performance
        $analysis = $this->analyzePerformance();
        
        // Optimize based on findings
        if ($analysis['hit_rate'] < 0.8) {
            $this->optimizeHitRate();
        }
        
        if ($analysis['memory_usage'] > 0.9) {
            $this->optimizeMemoryUsage();
        }
        
        if ($analysis['avg_get_time'] > 50) {
            $this->optimizeGetTime();
        }
        
        // Apply optimizations
        $this->applyOptimizations($analysis);
    }
    
    private function analyzePerformance()
    {
        $hitRate = $this->metrics->getHitRate();
        $memoryUsage = $this->metrics->getMemoryUsage();
        $performance = $this->metrics->getPerformance();
        $topKeys = $this->metrics->getTopKeys(100);
        
        return [
            'hit_rate' => $hitRate,
            'memory_usage' => $memoryUsage['used'] / $memoryUsage['total'],
            'avg_get_time' => $performance['avg_get_time'],
            'avg_set_time' => $performance['avg_set_time'],
            'top_keys' => $topKeys,
            'total_keys' => count($topKeys)
        ];
    }
    
    private function optimizeHitRate()
    {
        // Increase TTL for frequently accessed items
        $topKeys = $this->metrics->getTopKeys(50);
        
        foreach ($topKeys as $key => $hits) {
            if ($hits > 100) {
                // Get current value and extend TTL
                $value = $this->cache->get($key);
                if ($value !== null) {
                    $this->cache->put($key, $value, 7200); // Extend to 2 hours
                }
            }
        }
        
        // Pre-warm cache with predicted data
        $this->prewarmPredictedData();
    }
    
    private function optimizeMemoryUsage()
    {
        // Remove least used keys
        $leastUsed = $this->metrics->getLeastUsedKeys(100);
        
        foreach ($leastUsed as $key => $hits) {
            if ($hits < 5) {
                $this->cache->forget($key);
            }
        }
        
        // Compress large values
        $this->compressLargeValues();
        
        // Archive old data
        $this->archiveOldData();
    }
    
    private function optimizeGetTime()
    {
        // Switch to faster driver for high-traffic keys
        $highTrafficKeys = $this->metrics->getTopKeys(20);
        
        if (count($highTrafficKeys) > 0) {
            // Consider switching to Redis if using file cache
            $this->upgradeToFasterDriver();
        }
        
        // Optimize network settings
        $this->optimizeNetworkSettings();
    }
    
    private function prewarmPredictedData()
    {
        // Analyze access patterns
        $patterns = $this->analyzeAccessPatterns();
        
        // Pre-warm based on time-based patterns
        $hour = date('H');
        if (isset($patterns['hourly'][$hour])) {
            foreach ($patterns['hourly'][$hour] as $key) {
                if (!$this->cache->has($key)) {
                    $this->warmKey($key);
                }
            }
        }
        
        // Pre-warm based on user behavior
        $this->prewarmUserSpecificData();
    }
    
    private function compressLargeValues()
    {
        // Find large values
        $largeKeys = $this->metrics->getLargeKeys(50);
        
        foreach ($largeKeys as $key => $size) {
            if ($size > 1048576) { // 1MB
                $value = $this->cache->get($key);
                if ($value !== null) {
                    // Compress and re-store
                    $compressed = gzcompress(serialize($value), 9);
                    $this->cache->put($key, $compressed, 3600);
                }
            }
        }
    }
    
    private function upgradeToFasterDriver()
    {
        // This would involve configuration changes
        // to switch from file to Redis, for example
        config(['cache.default' => 'redis']);
        config(['cache.stores.redis.compression' => true]);
    }
    
    // Schedule optimization
    public function scheduleOptimization()
    {
        // Run optimization hourly
        schedule()->call(function() {
            $this->optimize();
        })->hourly();
        
        // Deep analysis daily
        schedule()->call(function() {
            $this->deepAnalysis();
        })->daily();
    }
}

Usage Examples

Common caching scenarios and implementation patterns for different use cases.

API Response Caching

class ApiResponseCache
{
    private $cache;
    
    public function __construct(CacheManager $cache)
    {
        $this->cache = $cache;
    }
    
    public function cacheApiResponse($request, $response, $ttl = 300)
    {
        $key = $this->generateCacheKey($request);
        
        // Add cache headers to response
        $response->headers->set('X-Cache', 'MISS');
        $response->headers->set('Cache-Control', "public, max-age={$ttl}");
        
        // Store in cache
        $this->cache->tags(['api', 'responses'])->put($key, [
            'status' => $response->getStatusCode(),
            'headers' => $response->headers->all(),
            'content' => $response->getContent()
        ], $ttl);
        
        return $response;
    }
    
    public function getCachedResponse($request)
    {
        $key = $this->generateCacheKey($request);
        
        $cached = $this->cache->tags(['api', 'responses'])->get($key);
        
        if ($cached) {
            // Create response from cache
            $response = new Response(
                $cached['content'],
                $cached['status'],
                $cached['headers']
            );
            
            $response->headers->set('X-Cache', 'HIT');
            
            return $response;
        }
        
        return null;
    }
    
    private function generateCacheKey($request)
    {
        $parts = [
            'api',
            $request->method(),
            $request->path(),
            md5(json_encode($request->all())),
            $request->header('Accept-Language', 'en'),
            $request->header('Accept', 'application/json')
        ];
        
        return implode(':', $parts);
    }
    
    // Middleware for API caching
    public function handle($request, $next, $ttl = 300)
    {
        // Check if caching is enabled
        if (!config('api.cache_enabled')) {
            return $next($request);
        }
        
        // Try to get cached response
        $cachedResponse = $this->getCachedResponse($request);
        
        if ($cachedResponse) {
            return $cachedResponse;
        }
        
        // Process request
        $response = $next($request);
        
        // Cache successful responses
        if ($response->isSuccessful()) {
            $this->cacheApiResponse($request, $response, $ttl);
        }
        
        return $response;
    }
}

// Usage in routes
Route::middleware('api.cache:600')->group(function() {
    Route::get('/api/users', 'UserController@index');
    Route::get('/api/posts', 'PostController@index');
    Route::get('/api/categories', 'CategoryController@index');
});

Session Caching

class CachedSessionHandler
{
    private $cache;
    private $ttl;
    
    public function __construct(CacheManager $cache, $ttl = 7200)
    {
        $this->cache = $cache;
        $this->ttl = $ttl;
    }
    
    public function read($sessionId)
    {
        $key = "session:{$sessionId}";
        
        $data = $this->cache->get($key);
        
        if ($data !== null) {
            // Extend TTL on access
            $this->cache->expire($key, $this->ttl);
            return $data;
        }
        
        return '';
    }
    
    public function write($sessionId, $data)
    {
        $key = "session:{$sessionId}";
        
        return $this->cache->put($key, $data, $this->ttl);
    }
    
    public function destroy($sessionId)
    {
        $key = "session:{$sessionId}";
        
        return $this->cache->forget($key);
    }
    
    public function gc($maxLifetime)
    {
        // Cache automatically handles expiration
        return true;
    }
    
    // Session data caching with user context
    public function cacheUserSession($userId, $sessionData)
    {
        $key = "user_session:{$userId}";
        
        // Store with user tags for invalidation
        $this->cache->tags(['sessions', "user:{$userId}"])->put($key, [
            'data' => $sessionData,
            'created_at' => now(),
            'last_activity' => now()
        ], $this->ttl);
        
        return true;
    }
    
    public function getUserSessions($userId)
    {
        $key = "user_session:{$userId}";
        
        return $this->cache->tags(['sessions', "user:{$userId}"])->get($key);
    }
    
    public function invalidateUserSessions($userId)
    {
        // Clear all sessions for a user
        $this->cache->tags(['sessions', "user:{$userId}"])->flush();
        
        return true;
    }
    
    // Session locking to prevent race conditions
    public function acquireSessionLock($sessionId, $timeout = 30)
    {
        $lockKey = "session_lock:{$sessionId}";
        
        return $this->cache->lock($lockKey, $timeout)->get();
    }
    
    public function releaseSessionLock($sessionId)
    {
        $lockKey = "session_lock:{$sessionId}";
        
        return $this->cache->lock($lockKey)->release();
    }
}

Database Query Caching

class QueryCache
{
    private $cache;
    
    public function __construct(CacheManager $cache)
    {
        $this->cache = $cache;
    }
    
    public function rememberQuery($query, $ttl = 3600)
    {
        // Generate cache key from query
        $key = $this->generateQueryKey($query);
        
        // Use cache tags based on tables
        $tables = $this->getQueryTables($query);
        $tags = array_merge(['queries'], $tables);
        
        return $this->cache->tags($tags)->remember($key, $ttl, function() use ($query) {
            return $query->get();
        });
    }
    
    public function rememberQueryFirst($query, $ttl = 3600)
    {
        $key = $this->generateQueryKey($query) . ':first';
        $tables = $this->getQueryTables($query);
        $tags = array_merge(['queries'], $tables);
        
        return $this->cache->tags($tags)->remember($key, $ttl, function() use ($query) {
            return $query->first();
        });
    }
    
    public function rememberQueryCount($query, $ttl = 3600)
    {
        $key = $this->generateQueryKey($query) . ':count';
        $tables = $this->getQueryTables($query);
        $tags = array_merge(['queries', 'counts'], $tables);
        
        return $this->cache->tags($tags)->remember($key, $ttl, function() use ($query) {
            return $query->count();
        });
    }
    
    public function flushQueryCache($tables = null)
    {
        if ($tables === null) {
            // Flush all query caches
            $this->cache->tags(['queries'])->flush();
        } else {
            // Flush specific table caches
            $tags = is_array($tables) ? $tables : [$tables];
            $this->cache->tags($tags)->flush();
        }
        
        return true;
    }
    
    private function generateQueryKey($query)
    {
        $sql = $query->toSql();
        $bindings = $query->getBindings();
        
        return 'query:' . md5($sql . serialize($bindings));
    }
    
    private function getQueryTables($query)
    {
        // Extract table names from query
        $sql = $query->toSql();
        preg_match_all('/FROM\s+`?(\w+)`?/', $sql, $matches);
        
        return $matches[1] ?? [];
    }
    
    // Model trait for caching
    public function cachedScope($query, $ttl = 3600)
    {
        return $this->rememberQuery($query, $ttl);
    }
    
    public function cachedRelation($relation, $ttl = 3600)
    {
        $key = "model:{$this->getTable()}:{$this->id}:relation:{$relation}";
        
        return $this->cache->tags(['models', $this->getTable()])->remember($key, $ttl, function() use ($relation) {
            return $this->$relation;
        });
    }
}

// Usage in models
trait Cacheable
{
    public function scopeCached($query, $ttl = 3600)
    {
        $cache = Container::getInstance()->make('cache');
        $queryCache = new QueryCache($cache);
        
        return $queryCache->rememberQuery($query, $ttl);
    }
    
    public function cachedRelation($relation, $ttl = 3600)
    {
        $cache = Container::getInstance()->make('cache');
        $key = "model:{$this->getTable()}:{$this->id}:relation:{$relation}";
        
        return $cache->tags(['models', $this->getTable()])->remember($key, $ttl, function() use ($relation) {
            return $this->$relation;
        });
    }
    
    public function clearCache()
    {
        $cache = Container::getInstance()->make('cache');
        
        // Clear model cache
        $cache->tags(['models', $this->getTable()])->flush();
        
        // Clear specific instance
        $cache->forget("model:{$this->getTable()}:{$this->id}");
        
        return true;
    }
}

// Usage
class User extends Model
{
    use Cacheable;
    
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// In controllers
$users = User::cached(3600)->get();
$posts = $user->cachedRelation('posts', 1800);

Best Practices

Recommended patterns and guidelines for working with the caching system.

Do's

  • • Use meaningful cache keys with namespaces
  • • Set appropriate TTL values
  • • Use cache tags for related data
  • • Implement cache invalidation strategies
  • • Monitor cache hit rates
  • • Use appropriate cache drivers
  • • Handle cache misses gracefully
  • • Implement cache warming
  • • Use compression for large data
  • • Test cache behavior under load

Don'ts

  • • Don't cache everything
  • • Don't use overly long TTLs
  • • Don't ignore cache expiration
  • • Don't cache sensitive data without encryption
  • • Don't rely on cache for critical data
  • • Don't ignore cache size limits
  • • Don't use cache as primary storage
  • • Don't ignore cache driver limitations
  • • Don't cache volatile data
  • • Don't skip cache invalidation