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 Contracts Laravel Package

symfony/cache-contracts

A set of cache abstractions extracted from Symfony components. It defines interfaces such as CacheInterface, CacheItemInterface, and TagAwareCacheInterface, letting libraries depend on proven cache semantics without binding to a concrete implementation.

View on GitHub
Deep Wiki
Context7

Getting Started

You almost certainly already have it. symfony/cache-contracts is a transitive dependency pulled in by symfony/cache, which Laravel has shipped with since 5.5. Verify with composer why symfony/cache-contracts — you won't normally add it explicitly.

Where to look first:

  • The interfaces themselves — vendor/symfony/cache-contracts/:
    • CacheInterface + CacheTrait (the "simple" PSR-16-ish API: get, set, delete, getMultiple, setMultiple, deleteMultiple, has, clear)
    • CacheItemPoolInterface (PSR-6 alias re-exported from psr/cache)
    • CacheItemInterface (PSR-6)
    • TagAwareCacheInterface + ItemInterface (Symfony extension: tag invalidation)
    • CallbackInterface (supports the CallbackInterface-based deferred save pattern)
  • Then look at Laravel's Illuminate\Cache\ArrayStore, Illuminate\Cache\RedisStore, and Illuminate\Cache\Repository to see how the framework actually consumes these concepts.

First use case for a Laravel dev: don't implement anything. Just confirm the contracts are available and reach for Cache facade as normal — Cache::remember(), Cache::tags([...])->flush(), etc. are already implemented on top of these abstractions. The contracts only become interesting when:

  1. You're writing a custom cache driver (e.g., DynamoDB, custom Redis cluster, CockroachDB-backed cache).
  2. You're writing a package that needs to accept any cache backend without pinning to Laravel's Cache facade.
  3. You're integrating a library that expects Psr\Cache\CacheItemPoolInterface (PSR-6) directly.

Implementation Patterns

Inject the contract, not the driver. In a service or package, type-hint Symfony\Contracts\Cache\CacheInterface (simple API) or Psr\Cache\CacheItemPoolInterface (PSR-6) rather than Illuminate\Contracts\Cache\Repository. In a Laravel service provider, bind a specific adapter:

$this->app->bind(CacheInterface::class, function ($app) {
    return new Psr16Cache(new ArrayAdapter()); // or FilesystemAdapter, RedisAdapter, ...
});

You'll typically pull the underlying adapter from symfony/cache — the contracts package has zero concrete implementations.

Custom Laravel driver (the classic use case). Implement Laravel's Illuminate\Contracts\Cache\Store and wire it into config/cache.php:

// config/cache.php
'dynamo' => ['driver' => 'dynamo', ...],
// AppServiceProvider::boot()
Cache::extend('dynamo', function ($app) {
    return Cache::repository(new DynamoStore(...));
});

If your driver needs to also satisfy third-party packages, additionally implement Psr\Cache\CacheItemPoolInterface on top of it (usually via Symfony\Component\Cache\Adapter\... or a thin wrapper).

Deferred/batched writes. Symfony's adapters support saveDeferred() + commit() for bulk writes (relevant when porting Symfony code into Laravel). In native Laravel, you'd lean on Cache::putMany() instead — the contracts don't add much here.

Tag invalidation. Laravel's Cache::tags([...])->flush() uses the same conceptual interface as Symfony's TagAwareCacheInterface, but they are different interfaces. Don't assume you can inject TagAwareCacheInterface and have Laravel pick it up — Laravel's TaggedCache is its own thing. Keep tags inside the Laravel facade; use TagAwareCacheInterface only if you're writing Symfony-compatible code.

Package authoring. If you publish a Laravel package that caches, type-hint CacheInterface and ship a Psr16Cache(ArrayAdapter::class) fallback so it works with or without Laravel's cache layer. This is the single biggest win the package gives you — a portable, tiny surface area to depend on.

Gotchas and Tips

  • It's interfaces only. symfony/cache-contracts won't cache anything by itself. You need symfony/cache (or another PSR-6/PSR-16 implementation) behind it. In Laravel this is a non-issue because the framework already includes it — but if you're writing a package, add symfony/cache to your require (or suggest).

  • PSR-6 vs PSR-16 vs Symfony "simple". Three different things are conflated in people's heads:

    • Psr\Cache\CacheItemPoolInterface — PSR-6, item-based (getItem, save).
    • Psr\SimpleCache\CacheInterface — PSR-16, key/value (get, set).
    • Symfony\Contracts\Cache\CacheInterface — Symfony's simple-cache-like interface, not strictly PSR-16. It's a subset with cache.get-style callbacks in the concrete adapters.

    If you need PSR-16 specifically, reach for Psr\SimpleCache\CacheInterface and bridge via Symfony\Component\Cache\Psr16Cache.

  • Version skew. symfony/cache-contracts v2/v3 aligns with Symfony 5/6+ and PSR-6/PSR-16 versions. Laravel pins a compatible range; if you composer require an incompatible version, composer will complain. Never force it. Use composer why symfony/cache-contracts to confirm the version pulled in by Laravel before adding an explicit constraint.

  • ArrayAdapter is memory-only. Great for tests (bind it in TestCase::setUp() to keep tests hermetic), useless in production since it doesn't persist across requests. This is the classic "why is my cache empty?" bug when a Symfony snippet is dropped into Laravel.

  • Serialization quirks vary by adapter. FilesystemAdapter and RedisAdapter serialize non-scalar values; some setups don't. If you're storing value objects, be explicit about serialization rather than relying on adapter defaults.

  • Debugging stale cache. php artisan cache:clear is the Laravel-side tool. There's no equivalent cache:clear from the contracts package — it just declares clear(). If a third-party package implements CacheInterface but no-ops clear(), you'll chase ghosts.

  • Extension points for custom adapters. If you must build from symfony/cache, extend AbstractAdapter and implement doFetch, doSave, doDelete, doClear. For a pure-Laravel driver, implement Illuminate\Contracts\Cache\Store instead — the contracts sit underneath, not beside, Laravel's abstraction, and mixing the two usually leads to bugs.

  • Don't depend on it directly unless you must. For application code, Illuminate\Contracts\Cache\Repository is the right abstraction. Reserve symfony/cache-contracts for interop boundaries (packages, Symfony-side libraries, PSR-6 consumers) so you don't accidentally couple business code to Symfony.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route