jeandormehl/laracache
Laracache is a lightweight Laravel package that provides a simple caching layer for your application. It works with Laravel's cache system to help speed up responses and reduce repetitive work, with straightforward helpers for storing and clearing cached data.
jeandormehl/laracache gives Laravel a cache store backed by InterSystems Caché / IRIS through the InterSystems PHP extension. It is the right tool when the Caché/IRIS instance is already the sanctioned data tier and standing up Redis or Memcached isn't an option — for example, existing healthcare or finance deployments where IRIS is the only approved datastore. Day to day you keep using the Cache facade; only the store underneath changes.
Minimal steps:
cache PHP extension must be loaded in both the web and CLI SAPIs:
php -m | grep -i cache
php -r 'var_dump(function_exists("cache_set"));'
If artisan can see the extension but FPM cannot, you will get a hard failure only in production.composer require jeandormehl/laracache. On 5.x, verify the php constraint in composer.json resolves against your runtime (see Gotchas — the major bump is the headline of this release).php artisan vendor:publish --provider="Jeandormehl\Laracache\...ServiceProvider") and fill in host, port (1972 by default), namespace, and credentials. Keep credentials in .env, not in the published file.config/cache.php:
'stores' => [
'iris' => [
'driver' => 'laracache',
'connection' => 'default',
],
],
Cache::store('iris')->put('health:probe', now()->toIso8601String(), 60);
Cache::store('iris')->get('health:probe');
First use case: point your existing rate limiter or a small "last sync" marker at the iris store rather than migrating the whole application cache at once. It exercises write, read, TTL expiry, and the connection pool under real traffic without risking session loss. Then look at the package's service provider and tests directory — the service provider tells you exactly which Store class and which capabilities (TaggableStore, LockProvider) the driver actually implements, which is the single most important fact for planning the rest of your usage.
Keep the default store on file/array and use iris explicitly. Swapping the application-wide default is tempting and usually a mistake: session, queue-failure, and framework-internal caches all inherit the new store, including its latency and outage characteristics. Cache::store('iris') at the call site keeps the blast radius small and makes the dependency visible in code review.
Wrap it in a thin repository, not scattered facade calls. A CacheRepository (or a small Cacheable trait) with remember, forget, and flushPrefix methods gives you one place to add try/catch fallbacks, one place to enforce key naming, and one place to change stores in tests.
Cache-aside with explicit invalidation is the only pattern that survives here. Since the backing store is a database-adjacent system, Cache::remember($key, $ttl, $callback) works well for read-heavy lookups, but always pair it with a forget inside your model observers (saved, deleted) so invalidation is event-driven rather than TTL-luck-driven.
Namespace hard by application and tenant. A shared IRIS instance is a shared keyspace. Set a distinct namespace/prefix per app and per environment, and prefix tenant-scoped keys (tenant:{id}:...). This also gives you a manual, greppable way to purge a single tenant's entries by iterating a known key list — cheap insurance if Cache::tags() isn't available on the driver.
Check for tags and locks before you design around them. If the store doesn't extend TaggableStore, Cache::store('iris')->tags([...]) throws at runtime, not at boot. The same applies to Cache::lock() unless the driver implements LockProvider. Grep your codebase for ->tags( and ->lock( and confirm support against the driver class before shipping. If tagging is unavailable, the prefix-based pattern above plus RateLimiter (which needs only atomic increments) covers most needs.
TTL semantics: be explicit. Always pass an integer number of seconds or a DateTimeInterface; avoid relying on a default. For forever() items, keep a companion index key listing them, otherwise they become undeletable without a flush.
Serialize conservatively. Store arrays, scalars, and DTOs that round-trip cleanly. Objects with closures, resources, or heavy Eloquent graphs are a recipe for large payloads and version-skew bugs on deploy. Prefer caching IDs plus a small hydration query over caching full models.
Warm the cache at deploy with an artisan command run after migrations, so the first user request after a release doesn't pay the cold-start cost against Caché.
php constraint and possibly dropped older minors. Before upgrading, run composer why-not jeandormehl/laracache 5.0.0 and read the diff on composer.json between v4.0 and 5.0.0. If you are still on PHP 8.1/8.2, stay on 4.x — that is the actual breaking change, not the PHP 8.5 feature itself.^8.5, but the InterSystems extension must have a matching binary for your platform and PHP version. Pin the extension version in your Docker image and CI matrix, and assert php -m | grep cache in a deploy smoke test. A missing extension typically manifests as a Class not found or connection exception at the first cache call, which is the worst time to find out.artisan tinker need the extension too. A cache warm-up command that works in your container but fails under cron is a classic.flush() is namespace-wide. On a shared IRIS instance it can wipe other applications' data. Never call Cache::flush() from application code; expose a targeted invalidation command instead, and treat flush as a DBA-only operation.^, $, and very long strings). Hash long or user-derived keys (sha1($key)) and keep the human-readable part as a short prefix.try/catch that logs and falls back to a file or array store, or better, to a null-object that returns null so the code path recomputes.Cache::fake() or the array store in feature/unit tests and reserve real-IRIS tests for a separate, gated integration suite. Never let CI depend on a live Caché server for the main test run.php artisan tinker against the named store, then check the IRIS audit/console log for the corresponding global writes. If writes appear to succeed but reads miss, suspect namespace or prefix mismatch between environments before suspecting the driver.How can I help you explore Laravel packages today?