Weave 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

Cache Laravel Package

symfony/cache

Symfony Cache provides fast, low-overhead PSR-6 and PSR-16 caching with adapters for popular backends, plus Symfony cache-contracts CacheInterface and TagAwareCacheInterface support.

View on GitHub
Deep Wiki
Context7

Getting Started

{Minimal steps, where to look first, first use case}

Minimal Setup in Laravel

To start using symfony/cache in Laravel, install the package via Composer:

composer require symfony/cache

First Use Case: Basic PSR-6 Cache

Leverage the CacheInterface for a simple in-memory cache:

use Symfony\Component\Cache\Adapter\ArrayAdapter;

// Create a basic cache instance
$cache = new ArrayAdapter();

// Store and retrieve data
$item = $cache->getItem('key');
$item->set('value');
$item->expiresAfter(3600); // 1 hour TTL
$cache->save($item);
$value = $cache->getItem('key')->get();

First Use Case: Redis Cache (Production)

Configure Redis via Laravel's cache config (config/cache.php) and use the adapter:

use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Psr16Cache;

$redisClient = new \Redis();
$redisClient->connect('127.0.0.1', 6379);

$cache = new RedisAdapter($redisClient, 'laravel_cache', 0);
$psr16Cache = new Psr16Cache($cache); // PSR-16 wrapper

First Use Case: Doctrine DBAL Cache

For database-backed caching:

use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter;
use Doctrine\DBAL\Connection;

$connection = // Your DBAL connection;
$cache = new DoctrineDbalAdapter($connection, 'laravel_cache', 0);

Implementation Patterns

1. PSR-6 Cache Integration

Use CacheInterface for low-level cache operations:

// Get an item, compute on miss, and persist
$item = $cache->getItem('user_42_profile');
if (!$item->isHit()) {
    $item->set(computeExpensiveValue());
    $item->expiresAfter(3600);
    $cache->save($item);
}
$value = $item->get();

// Delete and clear
$cache->deleteItem('user_42_profile');
$cache->clear();

2. PSR-16 Cache (Simple Key-Value)

Wrap PSR-6 cache in Psr16Cache for simplicity:

$psr16Cache = new Psr16Cache($cache);
$psr16Cache->set('key', 'value', 3600); // TTL in seconds
$value = $psr16Cache->get('key');

3. Tag-Aware Caching

Use TagAwareAdapter for grouped cache invalidation:

use Symfony\Component\Cache\Adapter\TagAwareAdapter;

// Create a tag-aware cache
$tagAwareCache = new TagAwareAdapter($cache);

// Store with tags
$item = $tagAwareCache->getItem('product_123');
$item->set($productData);
$item->tag(['products', 'category_electronics']);
$item->expiresAfter(3600);
$tagAwareCache->save($item);

// Invalidate by tag
$tagAwareCache->invalidateTags(['category_electronics']);

4. Chaining Adapters

Combine multiple caches (e.g., APCu + Redis):

use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;

$localCache = new ApcuAdapter();
$persistentCache = new RedisAdapter($redisClient, 'redis_', 0);

$chainCache = new ChainAdapter([$localCache, $persistentCache]);

5. Locking Mechanism

Prevent race conditions with LockFactory:

use Symfony\Component\Cache\Lock\LockFactory;

$lockFactory = new LockFactory($cache);
$lock = $lockFactory->createLock('unique_lock_key', 10); // 10-second TTL

if ($lock->acquire()) {
    try {
        // Critical section
    } finally {
        $lock->release();
    }
}

6. Encrypted Cache Values with SodiumMarshaller

Since v5.4.54, SodiumMarshaller gracefully handles values it cannot decrypt (e.g., after a key rotation) instead of throwing during unmarshalling. Wrap a real marshaller to add encryption on top of any adapter:

use Symfony\Component\Cache\Marshaller\SodiumMarshaller;
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
use Symfony\Component\Cache\Adapter\RedisAdapter;

// $decryptionKey is a base64-encoded sodium key (indexable by a key identifier)
$marshaller = new SodiumMarshaller(
    [$decryptionKey],
    new DefaultMarshaller()
);

$cache = new RedisAdapter($redisClient, 'laravel_', 0, $marshaller);

7. Laravel-Specific Integration

Extend Laravel's cache manager:

// config/cache.php
'stores' => [
    'symfony_redis' => [
        'driver' => 'symfony',
        'adapter' => 'redis',
        'connection' => 'default',
        'prefix' => 'laravel_',
    ],
],

// In a service provider
Cache::extend('symfony', function ($app) {
    $redis = Redis::connection('default');
    return new RedisAdapter($redis, 'laravel_', 0);
});

Gotchas and Tips

1. Prefix Handling

  • Gotcha: Prefixes must be alphanumeric or contain _/:. Invalid prefixes (e.g., /) will throw exceptions.
    // Valid
    $cache = new RedisAdapter($redis, 'laravel_', 0);
    
    // Invalid (throws exception)
    $cache = new RedisAdapter($redis, 'laravel/', 0);
    
  • Tip: Use consistent prefixes across environments (e.g., dev_, prod_).

2. Tag-Aware Cache Quirks

  • Gotcha: Tags are not automatically synced across chained adapters. Use TagAwareAdapter explicitly.
  • Tip: For complex tagging, implement a custom TagAwareAdapter or use AbstractTagAwareAdapter.
  • Tip: Call CacheItem::tag() on the item before save(); adding tags after save has no effect.

3. ChainAdapter Behavior

  • Gotcha: ChainAdapter stops at the first successful cache hit (no fallback to next adapter if the first fails).
  • Tip: Use ChainAdapter with a fast cache (e.g., APCu) first, followed by a persistent cache (e.g., Redis).

4. Locking Pitfalls

  • Gotcha: Locks do not block indefinitely. Always set a TTL to avoid deadlocks.
    // Bad: Risk of deadlock
    $lock->acquire(true); // Block forever
    
    // Good: Timeout after 10 seconds
    $lock->acquire(false, 10);
    
  • Tip: Use LockFactory with LockInterface for distributed locking (e.g., Redis, DBAL).

5. Serialization Issues

  • Gotcha: Non-serializable objects (e.g., closures, resources) cannot be cached.
    // Fails
    $cache->set('key', $nonSerializableObject);
    
    // Solution: Serialize manually
    $cache->set('key', serialize($object));
    
  • Tip: Use Symfony\Component\Serializer\SerializerInterface for complex objects.

6. SodiumMarshaller & Security Patch (v5.4.54)

  • Gotcha: Prior to v5.4.54, SodiumMarshaller would throw when unmarshalling a value it could not decrypt (e.g., after rotating encryption keys, or reading data written with a key no longer in the rotation list). If you use SodiumMarshaller, upgrade to at least v5.4.54 — it now skips (treats as a cache miss) values it cannot decrypt, so decryption failures no longer bubble up as errors.
  • Tip: Keep the previous key in the SodiumMarshaller keys array so that existing entries remain readable after rotation; the new behavior just means a stale/corrupt entry becomes a miss rather than an exception.
  • Tip: This is a [SECURITY] release — run composer audit and pin a minimum constraint like "symfony/cache": ">=5.4.54" for this branch (or the equivalent patch on newer branches).

7. Redis-Specific Tips

  • Gotcha: Redis TTL is set in seconds, not milliseconds.
    // Sets TTL to 1 hour (3600 seconds)
    $item->expiresAfter(3600);
    
  • Tip: Use RedisAdapter with RedisClusterAdapter for high availability:
    $redisCluster = new \RedisCluster();
    $cache = new RedisClusterAdapter($redisCluster, 'cluster_', 0);
    

8. Debugging Cache Issues

  • Tip: Enable Symfony's debug toolbar to inspect cache hits/misses (when using the framework bundle).
  • Tip: Use CacheItem::isHit() to check if a cache item was found:
    $item = $cache->getItem('key');
    if (!$item->isHit()) {
        $item->set(expensiveOperation());
        $cache->save($item);
    }
    
  • Tip: Swap to NullAdapter in tests when you want to force a miss without configuring a real backend.

9. Performance Optimization

  • Tip: Use ArrayAdapter for development (fast, in-memory) and switch to RedisAdapter/DoctrineDbalAdapter for production.
  • Tip: For high write throughput, consider ApcuAdapter (if APCu is available).
  • Tip: For batched operations, prefer getItems() / saveDeferred() + commit() over per-key calls to reduce round trips.

10. Security Considerations

  • Gotcha: Never cache sensitive data (e.g., passwords, tokens) unless encrypted — use SodiumMarshaller (see §6) or your own application-level encryption.
  • Tip: Use CacheItem::expiresAfter() with short TTLs for sensitive data:
    $item->expiresAfter(60); // 1 minute
    
  • Tip: Subscribe to the package's security advisories and keep the symfony/cache constraint patched; v5.4.54 is a security release.

11. Extending the Cache

  • Tip: Create custom adapters by extending AbstractAdapter or AbstractTagAwareAdapter.
  • Example: Custom cache with logging:
    use Symfony\Component\Cache\Adapter\AbstractAdapter;
    
    class LoggingAdapter extends AbstractAdapter {
        public function get($key, $default = null) {
            \Log::debug("Cache hit for key: {$key}");
            return parent::get($key, $default);
        }
    }
    
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo