cache/namespaced-cache
A PSR-6 decorator that scopes a shared cache pool to a single namespace, so clear() invalidates only that namespace. Includes tag support, generation-key safety, and | hierarchical key deletion.
What the package actually is
NamespacedCachePool wraps any Psr\Cache\CacheItemPoolInterface and transparently prefixes every key with a namespace string (e.g. acme:user:42). Callers see namespace-relative keys; the backend sees prefixed ones.HierarchicalPoolInterface from the php-cache family, so it composes with sibling decorators (e.g. cache/hierarchical-cache).php-cache/cache monorepo.Architecture fit
Illuminate\Contracts\Cache\Repository / CacheStore) is not PSR-6; it is a Laravel-specific contract with remember, tags, increment, and a prefix config option. There is no Cache::namespace(...) method, no auto-discovery, no container binding shipped by this package. Any such ergonomics would be code we write on top.php-http cache plugin, third-party SDKs that demand a PSR-6 pool). Here the decorator is genuinely useful glue.CacheItemPoolInterface, we need a pool adapter anyway; namespacing that pool costs one extra line.v1 → v2) is a cheap, atomic logical invalidation primitive for blue-green or canary rollouts, without touching keys at call sites.prefix, Cache::tags() (Redis/Memcached/array drivers), or a 20-line tenantKey() helper deliver equivalent isolation with zero third-party dependency and zero dependency-resolution risk. Build-vs-buy must be justified by cross-runtime reuse, not by Laravel use alone.Integration feasibility
psr/cache ^2.0/^3.0; a 1.x-era decorator pinned to psr/cache ^1.0 will conflict. This must be verified before any design work.Technical risk
clear() is namespace-scoped or delegates to a full-pool flush (a global flush in a multi-tenant cache is a data-loss incident), and whether namespace-wide operations rely on getItems() over the underlying pool — which on Redis can mean KEYS/SCAN and blocking I/O at scale.Key questions for engineering
psr/cache constraint resolve against our current lockfile? (Blocker check — do this first.)clear()'s exact scope, and what does a namespace-wide purge cost against our Redis topology?tenant:{id}, env:{name}, svc:{name}:v{n}), and who owns it as a contract?Stack fit matrix
| Context | Fit | Rationale |
|---|---|---|
| Laravel-only app, Redis/Memcached | Poor | Native prefix config, Cache::tags(), or a key helper cover it with no dependency. |
| Laravel app consuming PSR-6 libraries | Good | Needs a pool adapter regardless; namespacing is additive. |
| Shared cache across Laravel + non-Laravel services | Strong | The clearest justification: one convention across runtimes. |
| Symfony 6/7 services | Redundant | Symfony's cache config already exposes a namespace option per adapter. |
| Multi-tenant SaaS on a single Redis | Conditional | Only if clear() is proven namespace-scoped and key-prefix collision is enforced. |
Migration path
psr/cache, cache/* adapters) against the current lockfile on a throwaway branch. If it conflicts, stop and either fork or select an alternative. This phase kills or greenlights the initiative.NamespacedCachePool for a single low-risk consumer (feature flags or read-through reference data). Confirm clear() semantics with a destructive test in a sandboxed Redis DB."$tenant:" string concatenation).Compatibility concerns
~1.2) and record the resolved psr/cache version in the architecture decision record.psr/cache major.Sequencing guidance
Maintenance
Support
cache:clear now means for each pool.Scaling
maxmemory-policy.Failure modes
| Scenario | Impact | Mitigation |
|---|---|---|
clear() flushes the whole pool rather than one namespace |
Cross-tenant cache wipe; potential DB overload | Verify destructively in sandbox before adoption; forbid namespace purge in shared production pools if unscoped |
| Namespace typo or missing config | Silent 100% miss rate; thundering herd to origin | Fail-fast on unset namespace; alert on sudden per-namespace hit-rate drop |
| Namespace bump during deploy | Deliberate cold cache, latency spike | Schedule, pre-warm top-N keys, gate by canary |
| Prefix collision between services | Cross-service data leakage | Enforce taxonomy uniqueness in CI; reserve a per-service root segment |
Namespace-wide purge via getItems()/SCAN on a large Redis |
Blocked event loop, latency SLO breach | TTL-first invalidation; cap namespace size; purge out-of-band |
| Upstream stalls or dependency conflict appears | Upgrade blocked; forced fork | Documented fork path; pinned version; cheap exit strategy |
| Decorator composed in wrong order with tags | Silent invalidation failure | Integration test asserting tag invalidation through the decorator |
Ramp-up
TPM recommendation
Approve for a bounded POC only if a PSR-6 consumer or cross-runtime shared cache exists today, and only after the psr/cache constraint resolves cleanly. If the estate is Laravel-only, decline and fund a ~20-line key-prefix helper plus a CI lint rule instead — it delivers the isolation benefit with no dependency-resolution risk, no fork obligation, and no observability regression. Should the POC proceed, treat the package as a vendored internal utility with a documented exit, not as a strategic dependency.
How can I help you explore Laravel packages today?