assertchris / laravel-tagged-cache
A fluent tag-aware cache reference helper for Laravel.
Package info
github.com/assertchris/laravel-tagged-cache
pkg:composer/assertchris/laravel-tagged-cache
Requires
- php: >=8.2
- illuminate/cache: >=10.0
- illuminate/support: >=10.0
Requires (Dev)
- laravel/pint: 1.32.1
- orchestra/testbench: 11.2.0
- pestphp/pest: 5.2.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
One entry point, immutable tags, no boilerplate. Tag-scoped caching for Laravel.
Requirements
- PHP 8.2+
- Laravel 10+
- A tag-compatible cache driver (Redis or Memcached — not the
databaseorfiledriver)
Installation
composer require assertchris/laravel-tagged-cache
No service provider registration needed.
Concept
TaggedCache::for() binds a set of tags to a derived cache key. Every operation on that reference targets only that key, scoped to those tags. Tags are immutable after construction.
Flushing a tag clears every entry stored under it, regardless of key. That's the main reason to use tags.
Usage
The core pattern — remember on read, flush on write:
use AC\LaravelTaggedCache\TaggedCache; // Single entry TaggedCache::for(tags: ['notes'], context: ['id' => $note->id]) ->remember(now()->addHour(), fn () => $note->toArray()); // List query — full param set becomes the key TaggedCache::for(tags: ['notes'], context: $request->validated()) ->remember(now()->addHour(), fn () => Note::paginate()->toArray()); TaggedCache::for(tags: ['notes'])->flush(); TaggedCache::for(tags: ['notes'], context: ['id' => $note->id])->forget();
The flush() call with no context is the pattern to use in model observers — every saved, deleted, and restored hook just flushes the tag.
Other operations
$ref = TaggedCache::for(tags: ['notes'], context: ['id' => $note->id]); $ref->put($data, now()->addHour()); $ref->forever($data); $ref->rememberForever(fn () => $data); $ref->get(); $ref->has(); $ref->missing(); $ref->pull(); // get + delete atomically $ref->put(0, now()->addDay()); $ref->increment(); $ref->increment(4); $ref->decrement(2);
Key derivation
The cache key is md5(serialize(ksort($context ?: $tags))).
- If
contextis provided, we serialize and hash it. - If
contextis empty, we fall back to$tags. - The array is sorted by key before hashing —
['b' => 2, 'a' => 1]and['a' => 1, 'b' => 2]produce the same key, so passing$request->validated()is safe.
Keys are opaque and never user-facing.
Blocked methods
These methods aren't available on TaggedCache. They'll throw BadMethodCallException:
Blocked method list
| Method | Reason |
|---|---|
tags |
Would re-scope to different tags, breaking immutability |
clear |
Flushes the entire store, not just tagged entries |
setStore |
Replaces the underlying store for all callers |
setDefaultCacheTime |
Mutates shared TTL state on the underlying repository |
setEventDispatcher |
Mutates shared dispatcher state on the underlying repository |
Everything else proxies through __call and gets the derived key prepended automatically.
Full API surface
All available methods
TaggedCache::for(tags: ['tag'], context: ['key' => 'value']) ->get(default: null) ->has() ->missing() ->put(value: $data, ttl: now()->addHour()) ->add(value: $data, ttl: now()->addHour()) // only stores if key doesn't exist ->forget() ->pull(default: null) ->forever(value: $data) ->remember(ttl: now()->addHour(), callback: fn () => $data) ->rememberForever(callback: fn () => $data) ->increment(value: 1) ->decrement(value: 1) ->touch(ttl: now()->addHour()) // resets TTL without changing value ->flush() // flushes entire tag group, key is ignored