einar-hansen/laravel-psr-6-cache
Laravel package that bridges Laravel’s cache system with PSR-6. Use Laravel’s cache stores through a PSR-6 CacheItemPoolInterface for interoperability with PSR-compliant libraries, with simple configuration and drop-in integration.
Installation Require the package via Composer:
composer require einar-hansen/laravel-psr-6-cache
Service Provider Registration
Add the service provider to config/app.php under providers:
EinarHansen\Psr6Cache\Psr6CacheServiceProvider::class,
First Use Case
Inject CacheItemPoolInterface into a class and use it:
use Psr\Cache\CacheItemPoolInterface;
class MyService {
public function __construct(private CacheItemPoolInterface $cache) {}
public function getCachedValue(string $key): ?string
{
$item = $this->cache->getItem($key);
if (!$item->isHit()) {
$item->set('default_value')->expiresAfter(3600);
$this->cache->save($item);
}
return $item->get();
}
}
PSR-6 Cache Integration
Replace Laravel’s Cache:: facade with PSR-6 interfaces in services:
// Before (Laravel)
$value = Cache::remember('key', 3600, function () {
return 'value';
});
// After (PSR-6)
$item = $this->cache->getItem('key');
if (!$item->isHit()) {
$item->set('value')->expiresAfter(3600);
$this->cache->save($item);
}
return $item->get();
Leveraging Laravel’s Cache Drivers Configure the PSR-6 store to use an existing Laravel cache driver (e.g., Redis):
// config/cache.php
'stores' => [
'psr6' => [
'driver' => 'psr6',
'store' => 'redis', // Uses Laravel's Redis driver
],
],
Tag-Based Invalidation Use PSR-6 tags for bulk cache clearing (if the underlying driver supports it):
// Cache with tags
$item = $this->cache->getItem('user:123:data');
$item->set($data)->addTag('user:123');
$this->cache->save($item);
// Clear all tagged items
$this->cache->deleteItemsMatchingTag('user:123');
Middleware for PSR-6 Caching Cache API responses using PSR-6 in middleware:
public function handle($request, Closure $next)
{
$cacheKey = 'api_response_' . $request->path();
$item = $this->cache->getItem($cacheKey);
if ($item->isHit()) {
return response($item->get());
}
$response = $next($request);
$item->set($response->getContent())->expiresAfter(3600);
$this->cache->save($item);
return $response;
}
Custom Cache Item Wrappers Extend PSR-6 functionality with decorators:
class LoggedCacheItem implements CacheItemInterface {
private CacheItemInterface $item;
public function __construct(CacheItemInterface $item) {
$this->item = $item;
}
public function get() {
$value = $this->item->get();
Log::debug("Cache hit for key: {$this->item->getKey()}");
return $value;
}
// Delegate other methods to $this->item
}
Driver Limitations
file driver does not support tags (deleteItemsMatchingTag()). Use redis or database for tag-based caching.'psr6' => [
'driver' => 'psr6',
'store' => 'redis', // Supports tags
],
Key Prefix Conflicts
psr6_) may collide with existing keys. Customize it:
'psr6' => [
'prefix' => 'myapp_psr6_',
],
Lifetime Inconsistencies
expiresAfter() (seconds), while Laravel’s Cache::forever() uses null. Ensure consistency:
// PSR-6: Expires in 1 hour
$item->expiresAfter(3600);
// Laravel: Forever
Cache::put('key', 'value', null);
Serialization Issues
serialize()/unserialize() or JSON:
$item->set(json_encode($complexObject));
return json_decode($item->get());
No Native PSR-16 Support
Psr\SimpleCache\CacheInterface. Use CacheItemPoolInterface instead.Check Underlying Driver If PSR-6 operations fail, verify the configured Laravel driver (e.g., Redis) is running:
php artisan cache:clear
redis-cli ping
Log Cache Operations Wrap the cache to log hits/misses:
$this->cache->getItem('key')->isHit() ? Log::debug('Cache hit') : Log::debug('Cache miss');
Test with Mocks
Use PHPUnit to mock CacheItemPoolInterface for isolated testing:
$mockCache = $this->createMock(CacheItemPoolInterface::class);
$mockCache->method('getItem')->willReturn($this->createMock(CacheItemInterface::class));
Custom Cache Item
Override CacheItem behavior by binding a custom implementation:
$this->app->bind(CacheItemInterface::class, function ($app, $params) {
return new CustomCacheItem($params['key'], $app['cache.store']);
});
Event Listeners
Listen for PSR-6 cache events (e.g., CacheItem::expiresAt()) via Laravel events:
Cache::store('psr6')->extend(function ($app) {
$app->booting(function () {
Cache::store('psr6')->extend('events', function ($app) {
// Add custom logic
});
});
});
Fallback to Native Cache
Provide a fallback to Laravel’s Cache facade if PSR-6 fails:
try {
return $this->cache->getItem('key')->get();
} catch (\Exception $e) {
return Cache::get('key');
}
How can I help you explore Laravel packages today?