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

Illuminate Adapter Laravel Package

cache/illuminate-adapter

This package exposes an Illuminate cache store through PSR-6 and PSR-16, with tag support and hierarchical keys. Version 2 supports Illuminate 11 through 13. Pass any Illuminate\Contracts\Cache\Store implementation to the pool constructor.

View on GitHub
Deep Wiki
Context7

Getting Started

The package bridges two caching APIs: it makes an Illuminate\Contracts\Cache\Store (the low-level Laravel store, not the Repository facade) usable through the PSR-6 Psr\Cache\CacheItemPoolInterface. You keep every Laravel cache driver and configuration; you only change which interface your code talks to.

Install it:

composer require cache/illuminate-adapter

The two-line usage from the README, adapted to a real Laravel app:

use Cache\Adapter\Illuminate\IlluminateCachePool;
use Psr\Cache\CacheItemPoolInterface;

// Note ->getStore(): Cache::store() returns an Illuminate\Cache\Repository,
// the pool wants the underlying Store.
$this->app->singleton(CacheItemPoolInterface::class, function ($app) {
    return new IlluminateCachePool(
        $app['cache']->store('redis')->getStore()
    );
});

Register that binding in a service provider, then type-hint CacheItemPoolInterface anywhere — controllers, jobs, or third-party libraries (Doctrine, Symfony components, API clients) that demand PSR-6. That interface hint is the whole day-to-day value: your application code stops depending on Cache:: and starts depending on a standard.

Where to look first, in order:

  1. The README is ~15 lines. Don't expect more; it will not answer your questions.
  2. The actual source of IlluminateCachePool in the parent monorepo (php-cache/cache, under the Illuminate adapter directory). This repo is a read-only split — no code lives here, so read the class before you trust any behaviour.
  3. The shared php-cache docs at php-cache.com for hierarchy/tagging semantics, since this adapter inherits from cache/adapter-common.
  4. Your own test suite with ArrayStore. Given the package's low activity (11 stars, zero dependents), treat tests as the documentation.

First use case to prove out: cache-aside on a single read path.

$item = $this->pool->getItem('user_123_profile');
if (!$item->isHit()) {
    $item->set($this->repository->findProfile(123));
    $item->expiresAfter(300);          // seconds
    $this->pool->save($item);
}
return $item->get();

Run that against RedisStore in staging and ArrayStore in unit tests, then decide whether to expand.

Implementation Patterns

Interface binding, one pool per store. Bind a named singleton per cache role rather than reusing one pool everywhere — it keeps flush semantics and key spaces separated.

$this->app->singleton('cache.pool.sessions', fn ($app) =>
    new IlluminateCachePool($app['cache']->store('redis-sessions')->getStore())
);

Batch reads via getItems(). The main reason to adopt PSR-6 is multi-key fetch and multi-key invalidate in one round trip. When hydrating a collection:

$keys = array_map(fn ($id) => "product_{$id}", $ids);
$items = $pool->getItems($keys);
$misses = [];
foreach ($items as $key => $item) {
    if (!$item->isHit()) { $misses[] = $key; }
}
// resolve $misses in one query, then saveDeferred() + commit()

Use saveDeferred() then a single commit() for write-heavy loops; the adapter batches where the underlying store supports putMany().

Wrap the pool, don't fork it. Everything interesting happens at the boundaries: a decorator implementing CacheItemPoolInterface is the correct place for key namespacing, metrics, logging, and circuit-breaking.

final class NamespacedPool implements CacheItemPoolInterface
{
    public function __construct(
        private CacheItemPoolInterface $inner,
        private string $ns
    ) {}

    public function getItem(string $key): CacheItemInterface
    {
        return $this->inner->getItem($this->ns . $key);
    }
    // ...delegate the rest, prefixing keys
}

Wrap the store, too, if you need observability. Because the pool only speaks Store, a decorator around Illuminate\Contracts\Cache\Store that logs get/put/forget calls gives you a clean trace without touching the adapter.

Testing pattern. Use new ArrayStore() in unit tests and assert both hit and miss paths — including storage of falsy values (0, false, '', []), which is where cache adapters historically break.

$pool = new IlluminateCachePool(new ArrayStore());
$item = $pool->getItem('counter');
$item->set(0);
$pool->save($item);
$this->assertTrue($pool->getItem('counter')->isHit()); // must not be a miss

Migration pattern. Keep Cache:: for existing Laravel code and introduce the pool for new or third-party consumers, behind a feature flag. Only after you're confident, start converting call sites — see the interoperability gotcha below before you assume the two can share keys.

Gotchas and Tips

Cache::store('redis') is not a Store. The single most common first error: the pool constructor wants Illuminate\Contracts\Cache\Store. Always ->getStore(). The example in much of the surrounding marketing material (new IlluminateCachePool(Cache::store('redis'))) is wrong.

Key space is not shared with Laravel's API. If the adapter hashes or normalizes keys (many php-cache adapters do), then $pool->save() on user_123 and Cache::get('user_123') are looking at different keys. Verify with a spy: write through the pool, then try RedisStore::get() with the raw key and dump the actual Redis keys.

PSR-6 key rules are strict. Reserved characters { } ( ) / \ @ : are forbidden, and empty strings are forbidden. The tag-style keys floated in planning docs (user:123:profile) will throw InvalidArgumentException. Use user_123_profile. If you need hierarchy, encode it in the key yourself — the adapter won't parse it.

TTL units are the classic trap. PSR-6 expiresAfter() is seconds; Illuminate\Contracts\Cache\Store::put() takes minutes. Confirm what this adapter does at the boundary with a two-part test: expiresAfter(30) must not live for 30 minutes, and expiresAfter(null) must mean forever. Sub-minute TTLs are worth testing explicitly — many bridges silently round or drop them.

clear() is not scoped. It maps to Store::flush(), which on Redis wipes the whole connection's database and on DatabaseStore truncates the table. If the PSR-6 pool shares a Redis DB with Laravel's own cache, $pool->clear() will nuke both. Use a dedicated DB/prefix per pool, and prefer deleteItems() over clear() in application code.

Tagging does not come from Laravel. Cache::tags() lives on the Repository/TagSet layer and requires a TaggableStore. The pool operates on the raw store, so Laravel tags are not available through it. If you need tag invalidation, add the php-cache tagging decorator (cache/tag-interop semantics) on top of the pool; don't assume deleteByTag() works because the store is Redis.

Cache events won't fire. Repository dispatches CacheHit, CacheMissed, KeyWritten. The store-level adapter bypasses it, so anything relying on those events (Telescope, custom metrics) goes quiet for PSR-6 traffic.

No increment/decrement. PSR-6 has no counter API; you're limited to get-modify-save, which is racy. Keep counters on Cache::increment() and only route cache-aside reads through the pool.

ArrayStore is per-process. It is not shared across PHP-FPM workers. It's fine for tests and for building the pool binding; it is not a cache in production.

Laravel/PHP version drift is the real risk. The package has a tiny user base and no visible dependents. Before adopting, run the adapter's own test path against your Laravel version, and add a smoke test asserting getItem/save/deleteItems against DatabaseStore and MemcachedStore if you use them — the adapter's coverage there is unknown.

Pin and isolate. Require a specific version, keep the pool binding in one place, and wrap it in a decorator that catches adapter exceptions and degrades to a miss rather than throwing into your request path. That decorator is also your escape hatch if you ever swap to a first-party pool.

Fixes go upstream, not here. This repository is read-only. PRs belong in the php-cache/cache monorepo and issues on the php-cache tracker — budget for that before you plan on patching a bug locally.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core