swayok/alternative-laravel-cache
Alternative cache driver for Laravel that brings reliable tag support to any store—file, database, Redis, or Memcached—so you can group and invalidate keys without the limitations of Laravel's built-in tagged cache. Drop-in replacement with a familiar Cache::tags() API.
composer require <vendor>/<package>:^6.4. 6.4.0 builds on the 6.3.3 compatibility patch (no more direct reliance on Illuminate\Cache\CanFlushLocks, which is Laravel 13-only), so the package still installs and boots on Laravel 12 and earlier. If you were pinned to 6.3.2 or holding back laravel/framework, 6.4.0 is the version to move to.config/cache.php. 6.4.0 makes the file, Redis and Memcached stores honour config('cache.serializable_classes'), and adds a package-level config('cache.serializable_base_classes'). If neither key exists in your config yet, decide deliberately what belongs there rather than leaving it empty by accident.Filesystem instead of Flysystem, matching the framework's own file store, so custom wrappers, path assumptions, or permission handling around storage/framework/cache/data are the most likely breakage surface.// 1. serialization allowlist
Cache::put('demo', new App\Support\DemoDto(1), 60);
dump(Cache::get('demo')); // object round-trips? or silently null?
// 2. file store still reads/writes
Cache::store('file')->put('demo-file', ['ok' => true], 60);
dump(Cache::store('file')->get('demo-file'));
// 3. lock flush behaviour (carried over from 6.3.3)
Cache::lock('demo-lock', 10)->get(fn () => 'ok');
Artisan::call('cache:clear');
dump(Cache::lock('demo-lock', 10)->get()); // still acquirable?
unserialize() allowlists / allowed_classes juggling in a custom cache repository with the package's config-driven serialization. One config key, applied consistently across file/Redis/Memcached, instead of per-store guesswork.cache.serializable_classes. Cache small, explicit classes — not whole Eloquent models with relation graphs — and treat the list as a security boundary, because it is what gates deserialization of whatever is sitting in Redis or on disk.serializable_base_classes for the "many subclasses" case. If you have a family of objects (e.g. every App\Domain\Events\* or anything implementing a marker interface), listing each concrete class becomes unmaintainable. This package-only key exists for exactly that; keep it as tight as you can — abstract bases and narrow interfaces, not stdClass or a broad root interface.Cache::lock($key, 1)->get() should succeed after a flush, and a cached DTO should come back as the DTO class (not __PHP_Incomplete_Class, not null).array proves nothing about allowlist behaviour. Add at least one test that runs against file or redis.serializable_classes handling is another place where framework version can matter.null back or a __PHP_Incomplete_Class. A cache that "stopped working" right after upgrading usually means the payload class isn't listed. Assert on the returned type, not just non-null.Filesystem in the file store is a real internal swap. Check: does anything in your code rely on Flysystem adapters, visibility, or streams for the file cache? Do the cache directories still have the right owner/permissions? If you extended or mocked the file store, your test doubles may no longer line up.cache.serializable_classes mirrors the framework's key; cache.serializable_base_classes is package-specific. Don't assume every Laravel version ships or reads both — guard on framework version or config()->has() when your app supports a wide range.array pass while Redis fails in production. Test the serialization path against a store that actually round-trips bytes.Redis::get($key), or read the file under storage/framework/cache/data) and inspect the serialized payload. If the class name is right but hydration fails, it's an allowlist problem; if the payload is missing, it's a store/keyspace problem — different bugs.CanFlushLocks usage; 6.4.0 doesn't restore it. After any flush, test that the lock is actually gone rather than trusting a successful return, and avoid referencing CanFlushLocks in your own code (interface_exists() guard if you must).How can I help you explore Laravel packages today?