toflar/psr6-symfony-http-cache-store
PSR-6 compatible store for Symfony HttpCache using Symfony Cache + Lock. Adds tag-based invalidation, automatic pruning of expired entries, configurable adapters/locks, and BinaryFileResponse support. Avoids unbounded cache directory growth.
Installation
composer require toflar/psr6-symfony-http-cache-store:^4.3
Requires PHP 8.1+ and is compatible with Symfony 8. Add to your config/cache.php under stores:
'http_cache' => [
'driver' => 'toflar_psr6_http_cache',
'options' => [
'cache_dir' => storage_path('framework/cache/http'),
'cache_pool' => 'cache.array', // Your PSR-6 cache pool (e.g., Redis, APCu)
'ttl' => 3600, // Default TTL in seconds
],
],
First Use Case
Replace Symfony’s default HttpCache store in your HttpCache configuration (e.g., config/packages/symfony_http_cache.yaml):
framework:
http_cache:
store: \Toflar\Psr6SymfonyHttpCacheStore\Store
Now leverage PSR-6 cache pools (e.g., Redis, APCu) for storage while keeping Symfony’s HTTP cache logic.
Tag-Based Invalidation Use tags to invalidate related cache entries (e.g., by product ID or user role):
$cachePool->deleteTagged('product_123'); // Invalidates all entries tagged with 'product_123'
Note: Ensure your PSR-6 pool supports tags (e.g., cache.redis or cache.database; cache.array does not).
Auto-Pruning
Configure pruning in options:
'prune' => [
'interval' => 3600, // Check every hour
'max_entries' => 10000, // Keep at most 10k entries
'ttl_threshold' => 300, // Ignore entries expiring within 5 minutes
],
Run pruning manually via:
$store->prune();
TTL Overrides Set per-entry TTLs:
$store->save($request, $response, new \DateInterval('PT1H')); // 1-hour TTL
config/packages/symfony_http_cache.yaml:
framework:
http_cache:
store: \Toflar\Psr6SymfonyHttpCacheStore\Store
$store = new Store($cachePool, $cacheDir, $ttl);
HttpCacheStoreEvents (e.g., CacheMiss, CacheHit) for analytics or logging:
$this->eventDispatcher->addListener(
\Toflar\Psr6SymfonyHttpCacheStore\Event\HttpCacheStoreEvents::CACHE_MISS,
fn($event) => \Log::debug('Cache miss for: ' . $event->getRequest()->getUri())
);
Tagging Limitations
cache.redis or cache.database; cache.array does not).predis/predis or doctrine/cache.Pruning Overhead
TTL Granularity
prune['ttl_threshold'] to ignore entries near expiration.PHP/Symfony Version Compatibility
'prune' => [
'debug' => true, // Logs pruned entries
],
HttpCacheEventListener to log events:
$this->eventDispatcher->addListener(
\Toflar\Psr6SymfonyHttpCacheStore\Event\HttpCacheStoreEvents::CACHE_MISS,
fn($event) => \Log::debug('Cache miss for: ' . $event->getRequest()->getUri())
);
Store and override prune():
class CustomStore extends Store {
protected function prune(): void {
// Custom logic (e.g., exclude certain tags)
parent::prune();
}
}
cache-key:metadata) by extending CacheEntry:
$entry = new CacheEntry($request, $response, $ttl);
$entry->setMetadata(['user_id' => auth()->id()]);
$this->save($entry);
getVaryHeaders() to customize cache keys:
$store->setVaryHeaders(['Accept-Language', 'User-Agent']);
class ExtendedStore extends Store {
public const MAX_TTL = 86400; // Typed constant (PHP 8.5+)
}
How can I help you explore Laravel packages today?