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

Simple Cache Bridge Laravel Package

cache/simple-cache-bridge

Exposes an existing PSR-6 cache pool through the PSR-16 CacheInterface, letting you reuse one pool for both standards. Install with composer require cache/simple-cache-bridge:^2.0. Supports psr/cache 3 and psr/simple-cache 2 and 3.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit Single-class adapter, MIT, split out of the php-cache monorepo and explicitly marked [READ-ONLY] — all issues and PRs route to a separate upstream tracker. It does exactly one thing: present an existing Psr\Cache\CacheItemPoolInterface as a Psr\SimpleCache\CacheInterface. There is no service provider, no config surface, no facade, and no Laravel coupling. It is a library, not an integration, and that is the correct framing for the decision.

The fit is narrow and conditional: it is justified only when we already own a PSR-6 pool we cannot replace — a vendor library handing us a CacheItemPoolInterface, a legacy Symfony/php-cache adapter, or a store whose only implementation is PSR-6 — and a consumer type-hints PSR-16. For everything else it is an extra layer with no product value.

One correction to carry into the decision record: Laravel natively adapts its own stores to both PSR-6 (Illuminate\Cache\Psr6Cache) and PSR-16 (Illuminate\Cache\Psr16Cache), but it does not convert an arbitrary third-party PSR-6 pool into PSR-16. So the package is redundant for Laravel-native stores and genuinely fills a gap for external pools — a gap symfony/cache's Psr16Cache also fills, with a far larger install base. The real architectural question is not "bridge or no bridge" but "which bridge, and can we eliminate the need for one."

Integration feasibility Low effort, low ceremony, no data migration. composer require cache/simple-cache-bridge:^2.0, construct with a pool, bind the resulting CacheInterface as a singleton, inject it. Realistic estimate: half a day for a conformance spike plus a thin internal adapter; one to two days end-to-end including config plumbing and a feature-flagged rollout. Version 2 targets psr/cache 3 and supports psr/simple-cache 2 and 3, which aligns with current Laravel-era dependency ranges.

Two feasibility traps to validate before committing:

  • Cache::extend() is the wrong hook. The callback registered with Laravel's cache manager must return an Illuminate\Contracts\Cache\Store, not a PSR-16 instance. Registering this bridge as a custom CACHE_DRIVER is not a supported path and will fail at resolution time. The supported pattern is a container binding for Psr\SimpleCache\CacheInterface plus constructor injection into the services that need it.
  • Semantic ceiling. PSR-16 is deliberately lossy: no tags, no per-item expiresAfter(), no getItems() batching, no CAS. Everything downstream of the bridge gets the lowest common denominator, and tag-based invalidation in particular does not survive the crossing.

Technical risk Medium-to-high, and almost entirely supply-side rather than engineering-side:

  • Maintenance concentration. 42 stars, zero dependents, single-organisation stewardship, release notes that are pointers to a changelog rather than substantive detail. Effectively unexercised in the wild — we would be among the first production users.
  • Version ceiling / runtime coverage. Documentation reflects testing against older PHP runtimes; PHP 8.1+ behaviour and any future PSR-16 conformance tightening are unverified. We must test compatibility ourselves rather than assume it.
  • Exception-contract mismatch. PSR-6 surfaces Psr\Cache\InvalidArgumentException/CacheException; PSR-16 requires the Psr\SimpleCache equivalents. Whether the bridge translates these is a concrete, testable question — a leak here turns a cache fault into an uncaught 500 instead of a graceful miss.
  • TTL semantics. PSR-16 treats null as "use default" and 0/negative as "delete"; PSR-6 uses expiresAfter(). Misalignment silently shortens or extends item lifetimes, surfacing as inexplicable hit-ratio drift rather than an error.
  • Batch amplification. setMultiple/getMultiple/deleteMultiple are near-certainly loops over single-key PSR-6 calls, multiplying network round-trips against Redis/Memcached.

Key questions

  1. What is the specific PSR-6 pool we must keep, and what blocks replacing it with a native PSR-16 implementation (symfony/cache's Psr16Cache, or a Laravel store)?
  2. Which consumers actually need Psr\SimpleCache\CacheInterface rather than Laravel's Illuminate\Contracts\Cache\Repository? If the answer is "none," this is optional dependency debt.
  3. Does the bridge translate PSR-6 exceptions to PSR-16 exceptions? Prove it with a failing-backend test.
  4. How does default_ttl behave across set()/setMultiple() when the underlying pool carries its own default lifetime?
  5. Do any consumers rely on tagging or getItems()? If so, the bridge is disqualified and we need a different seam.
  6. Who owns the fork or in-house reimplementation if upstream goes dormant, and what is our maximum acceptable time-to-replace?

Integration Approach

Stack fit A thin internal wrapper is the right shape: bind Psr\SimpleCache\CacheInterface to a singleton built from our existing pool, and let Laravel's repository remain the default for all new code. Do not attempt to expose this as a CACHE_DRIVER, and do not wire it through Cache::extend(). Keep the vendor class behind exactly one internal factory so no application code names it directly.

Migration path Non-destructive by construction — the bridge delegates to the pool we already have, so keys, TTLs, and stored values are untouched. That means zero backfill, zero dual-write, and a trivially reversible switch: remove the binding and consumers revert to whatever they used before. This reversibility is the package's strongest product argument and should be the basis of the go/no-go.

Compatibility Pin to an exact version, commit the lockfile, and build a compatibility matrix in our own suite (supported PHP versions × production cache backend × hit/miss/expiry/exception paths). Treat upstream as frozen: no ^ ranges, no automated dependency bumps. If symfony/cache can serve the same pool, prefer it — same abstraction, vastly larger install base — and reserve this package for cases where its pool expectations are already proven in our environment.

Sequencing

  1. Spike (0.5 day): wrap the candidate pool and assert PSR-16 conformance on get/set/delete/clear, the *Multiple methods, TTL edge cases (null, 0, negative), and exception translation against a deliberately failing backend.
  2. Adapter (0.5 day): internal SimpleCacheFactory plus container binding, so replacement later is a one-file change.
  3. Contract test + observability (0.5 day): hit/miss counters and a latency histogram tagged by operation, so we can prove the bridge is not degrading the pool.
  4. Canary rollout (1–3 days): enable for one low-risk consumer — a read-through cache in a background job — and compare hit ratio and p95 against the incumbent across a full eviction cycle.
  5. Broaden or exit: promote only if metrics are flat; otherwise delete the binding. Reversal costs near zero, which is precisely why the spike is worth doing.

Operational Impact

Maintenance Near-zero code churn, non-trivial dependency governance. The package is a few hundred lines of delegation logic; if upstream disappears, vendoring or a ~150-line in-house reimplementation is a day's work. Budget that day in the plan rather than treating it as an emergency. The [READ-ONLY] split repo means bug reports cross a repository boundary — assign a named internal owner, because nobody upstream will triage on our timeline.

Support No SLA, community channel only, no vendor behind it. The realistic support model is "we own it the moment we ship it." Mitigate by keeping the vendor class behind a single internal class so support questions never become archaeology across the codebase, and by documenting the "use this only if…" rule in the ADR.

Scaling No material CPU or memory overhead — one extra method call per operation. The scaling risk is amplification, not unit cost: if setMultiple/getMultiple fan out to N single-key PSR-6 calls, a 500-key batch becomes 500 round-trips where a native implementation would pipeline. Measure before using batch APIs in hot paths; prefer per-key access with application-side concurrency, or bypass the bridge for bulk jobs entirely.

Failure modes

  • Exception leakage: PSR-6 exceptions escaping into PSR-16-typed call sites, surfacing as 500s on cache faults rather than graceful misses.
  • Silent TTL divergence: bridge default and pool default disagree, so items expire earlier or later than the code assumes — visible as hit-ratio drift, not an alert.
  • Batch amplification: latency spikes under bulk load, invisible in single-key benchmarks.
  • Pool scoping: a request-scoped pool captured behind a singleton binding produces stale or disconnected pools in long-running queue workers — the classic Octane/queue-worker trap. Verify the pool is safe to hold for the worker's lifetime.
  • Feature loss: consumers written expecting tagging or per-item expiry get no-ops or runtime exceptions, discovered in production rather than review.
  • Abandonment: no security or PHP-version updates; mitigated by exact pinning plus the internal adapter seam.

Ramp-up Low technically — half a day for any engineer fluent in PSR interfaces, and the README is sufficient. The real ramp-up cost is organisational: teaching the team when to reach for the bridge (interfacing with a legacy PSR-6 pool) versus when to use Laravel's native repository (almost everything else). Left undocumented, this becomes a second, parallel caching idiom in the codebase — a larger long-term cost than the dependency itself.

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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator