Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Psr6 Symfony Http Cache Store Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. 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
        ],
    ],
    
  2. 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.


Implementation Patterns

Workflows

  1. 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).

  2. 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();
    
  3. TTL Overrides Set per-entry TTLs:

    $store->save($request, $response, new \DateInterval('PT1H')); // 1-hour TTL
    

Integration Tips

  • With Symfony HTTP Cache Middleware Replace the default store in config/packages/symfony_http_cache.yaml:
    framework:
        http_cache:
            store: \Toflar\Psr6SymfonyHttpCacheStore\Store
    
  • Custom Cache Pools Inject your PSR-6 pool via service container (e.g., Redis, Doctrine Cache):
    $store = new Store($cachePool, $cacheDir, $ttl);
    
  • Event Listeners Hook into 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())
    );
    

Gotchas and Tips

Pitfalls

  1. Tagging Limitations

    • Tags are not automatically synced with the underlying PSR-6 pool. Ensure your pool supports tags (e.g., cache.redis or cache.database; cache.array does not).
    • Fix: Use a tag-aware pool like predis/predis or doctrine/cache.
  2. Pruning Overhead

    • Frequent pruning on large caches may impact performance.
    • Fix: Schedule pruning during low-traffic periods or use a background job (e.g., Laravel Queues).
  3. TTL Granularity

    • The store uses the shortest TTL of all entries during pruning. Override with prune['ttl_threshold'] to ignore entries near expiration.
  4. PHP/Symfony Version Compatibility

    • Breaking: Requires PHP 8.1+ and Symfony 8. Older versions (e.g., PHP 8.0, Symfony 7) are no longer supported.
    • Fix: Update dependencies if migrating from older versions.

Debugging

  • Log Pruning Enable debug mode in config:
    'prune' => [
        'debug' => true, // Logs pruned entries
    ],
    
  • Check Cache Hits/Misses Use Symfony’s HttpCacheEventListener to log events:
    $this->eventDispatcher->addListener(
        \Toflar\Psr6SymfonyHttpCacheStore\Event\HttpCacheStoreEvents::CACHE_MISS,
        fn($event) => \Log::debug('Cache miss for: ' . $event->getRequest()->getUri())
    );
    

Extension Points

  1. Custom Pruning Logic Extend Store and override prune():
    class CustomStore extends Store {
        protected function prune(): void {
            // Custom logic (e.g., exclude certain tags)
            parent::prune();
        }
    }
    
  2. Add Metadata Store extra metadata (e.g., cache-key:metadata) by extending CacheEntry:
    $entry = new CacheEntry($request, $response, $ttl);
    $entry->setMetadata(['user_id' => auth()->id()]);
    $this->save($entry);
    
  3. HTTP Headers Override getVaryHeaders() to customize cache keys:
    $store->setVaryHeaders(['Accept-Language', 'User-Agent']);
    
  4. PHP 8.5 Features Leverage PHP 8.5 features (e.g., typed class constants, new attributes) in custom extensions:
    class ExtendedStore extends Store {
        public const MAX_TTL = 86400; // Typed constant (PHP 8.5+)
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor