spatie/laravel-flexible-cache-polyfill
Polyfill for Laravel 10 that adds Cache::flexible() (introduced in Laravel 11). Implements stale-while-revalidate caching so expired values can be served immediately while recalculation runs in the background, avoiding slow responses.
Installation:
composer require spatie/laravel-flexible-cache-polyfill
No publisher or configuration required—just add the package to your composer.json.
First Use Case:
Replace Cache::remember() with Cache::flexible() for stale-while-revalidate (SWR) behavior in Laravel 10:
$value = Cache::flexible('key', now()->addMinutes(5), function () {
return ExpensiveOperation::run();
});
remember, flexible serves stale data immediately if the cache is expired, while revalidating in the background.Where to Look First:
flexible() (for behavior reference).Migrating from remember to flexible:
$data = Cache::remember('expensive_key', 300, fn() => fetchFromDatabase());
$data = Cache::flexible('expensive_key', 300, fn() => fetchFromDatabase());
Combining with Other Cache Methods:
flexible alongside put()/get() for hybrid caching:
Cache::put('fallback_key', $fallbackValue, 60);
$value = Cache::flexible('primary_key', 300, fn() => generatePrimaryValue());
return $value ?? Cache::get('fallback_key');
Dynamic TTLs:
$ttl = Auth::user()->isPremium() ? 3600 : 600;
$data = Cache::flexible('user_data', $ttl, fn() => fetchUserData());
Tag-Based Invalidation:
file/database driver) to invalidate related keys:
Cache::flexible('product_123', 300, fn() => getProduct(123), tags: ['products']);
Cache::tags('products')->flush(); // Invalidates all tagged keys
Cache::shouldReceive('flexible')->andReturnUsing(...) in PHPUnit to mock responses:
Cache::shouldReceive('flexible')
->with('key', 300, $callback)
->andReturnUsing(fn($key, $ttl, $callback) => $callback());
Cache::flexible('key', 300, fn() => {
Log::debug('Cache miss for key', ['key' => 'key']);
return expensiveOperation();
});
Driver Limitations:
flexible behaves like remember.remember instead for these drivers.Race Conditions:
Cache::put() after revalidation to force freshness.Callback Execution:
Laravel 10 vs. 11:
flexible() but lacks some features (e.g., tags parameter in older Laravel 10). Check the package’s changelog for updates.if (Cache::has('key')) {
$stale = Cache::get('key');
$fresh = Cache::flexible('key', 300, fn() => 'fresh');
dd(['stale' => $stale, 'fresh' => $fresh]); // Should show stale first, then fresh.
}
Cache::stale events (if using Laravel 11+ features) or log manually:
Cache::extend('flexible', fn() => Cache::store('redis')->driver())->extend('flexible', function ($app) {
return Cache::repository(new FlexibleCacheStore($app['cache.stores.redis']));
});
Spatie\Cache\FlexibleCacheStore:
Cache::extend('database', fn() => Cache::repository(new FlexibleDatabaseCacheStore(
Cache::store('database')->driver()
)));
public function handle(Request $request, Closure $next) {
Cache::shouldUseFlexible = true; // Hypothetical; check package for actual API.
return $next($request);
}
Cache::get() to handle missing keys gracefully:
$value = Cache::flexible('key', 300, fn() => defaultValue()) ?? Cache::get('fallback_key');
How can I help you explore Laravel packages today?