Download the PHP package trm42/cache-decorator without Composer
On this page you can find all versions of the php package trm42/cache-decorator. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download trm42/cache-decorator
More information about trm42/cache-decorator
Files in trm42/cache-decorator
Package cache-decorator
Short Description Magical (as in saves manual work quite a lot) Cache Decorator for Laravel 5. Designed for usage with repositories but easily usable for other uses. If there's enough interest, can be made framework agnostic.
License GPL-2.0
Informations about the package cache-decorator
(Magical) Cache Decorator for Laravel
A transparent caching decorator for any Laravel-side class — services, API clients, query objects, repositories, you name it. Sub-class CacheDecorator, point it at the object you want to cache, and every public method call is automatically cached on first run and served from the cache on subsequent calls.
Stop writing boilerplate like this for every class whose results you want to cache:
With CacheDecorator the above shrinks to:
TTL is read from config, not from a
$ttlproperty. The constructor callsgetConfig(), which overwrites$ttlfromcache_decorator.ttl(default300seconds;repository_cache.ttlforRepositoryCacheDecorator). To override it per-instance, call->ttl(...)after construction (e.g. in your subclass constructor) — it acceptsintseconds, aDateInterval, aDateTimeInterface, ornullto bypass the cache entirely. See Fluent configuration for the full chainable grammar.
…and use it like this:
The decorator forwards any method not listed in $excludes to the underlying object via __call() and caches the result. Forwarding goes through Laravel's ForwardsCalls trait, so calls also reach methods the decorated object exposes through its own __call() magic — not just declared methods. Calling a method that exists nowhere on the decorated object throws UndefinedMethodException (see Object arguments in cache keys.
Fluent configuration
Every configuration setter is chainable (returns the decorator) and there's an expressive, self-documenting grammar for tuning an instance at runtime — no subclass property edits required:
| Method | Returns | Behavior |
|---|---|---|
ttl($ttl) |
static |
Set TTL (seconds / DateInterval / DateTimeInterface / null to bypass). |
enable() |
static |
Turn caching on. |
disable() |
static |
Turn caching off (forwards straight to the inner object). |
prefix(?string) |
static |
Set the cache-key prefix. |
withTags(array) |
static |
Set the cache tags. |
tagCleaners(array) |
static |
Set the methods that flush the tags. |
exclude(string ...) |
static |
Append method names to the never-cache list. |
If you add your own public methods to a
CacheDecoratorsubclass, remember that any method not listed in$excludesis forwarded to the inner object by__call(). The fluent methods above are already excluded by the base class, so chaining always resolves on the decorator and never leaks to the inner instance.
Object arguments in cache keys
Method arguments may be scalars, arrays, or objects — the decorator folds each argument into the cache key through a stable identity rule:
- Scalars /
null/bool— cast as-is (existing scalar-only keys are byte-identical, so upgrading invalidates nothing). UrlRoutable(Eloquent models, etc.) — usesgetRouteKey(), the model's natural stable identity. Two distinct instances with the same route key share a cache entry.BackedEnum— uses its->value;Stringable/__toString— string-cast.- Anything else (plain objects, nested arrays of objects) — a bounded, stable hash (
json_encode, falling back tomd5(serialize(...))).
Arrays are flattened (Arr::dot) and each leaf runs through the same rule, so nested objects are handled too.
To customize how a given argument type contributes to the key, override the protected normalizeArgument(mixed $value): string seam in your subclass — it sits alongside generateCacheKey(), getCache(), and putCache() as a first-class extension point.
Fluent / self-returning methods
forwardDecoratedCallTo() rewrites a fluent return $this; from the inner object back to the decorator, so method chaining stays on the cached surface instead of escaping to the bare inner instance.
Two conventions make this transparent and type-safe:
- List fluent methods in
$excludes. They aren't cache candidates anyway, and excluding them keeps them on the always-forward path. (On a cache miss__call()storescallMethod()'s return — now the decorator instance — and a later hit would return that cached decorator directly, bypassing the rewrite. Excluding avoids caching a decorator object.) - Type fluent methods
: staticbehind a shared interface. Have the inner class implement an interface whose fluent methods returnstatic. A caller then sees the same type whether it holds the inner instance or the decorator, and the decorator standing in for$thison self-returning calls is type-coherent.
Optional: have the decorator instantiate the inner class for you
If you don't want to wire the inner instance yourself, override decoratedClass() to return its FQCN and you can construct the decorator with no arguments:
The FQCN returned by decoratedClass() is resolved through Laravel's service container (via resolve()), so the decorated class may declare constructor dependencies (they are auto-wired), and decoratedClass() may return an interface that's bound in the container.
Custom caching logic for a single method
If a particular method needs hand-tuned caching, override it in the subclass and use the protected helpers:
getCache() returns the cacheMiss() sentinel (a shared stdClass instance) when the entry is absent — comparing with === against cacheMiss() lets the override round-trip falsy payloads (0, '', [], false, null) correctly. Don't use truthiness checks like if (!$res): they would treat a legitimately cached false/0/[] as a miss and refetch on every call.
Cache tags
If your cache driver supports tags, declare which methods invalidate the tag bucket:
Exceptions
All errors thrown by the package live in the Trm42\CacheDecorator\Exceptions namespace and extend a single abstract base, CacheDecoratorException. Catch that base type to handle any cache-decorator-specific failure in one place, or catch a concrete subclass to distinguish the failure mode:
| Exception | Thrown when |
|---|---|
CacheDecoratorException |
(abstract base — never thrown directly; catch it to handle every error below) |
MissingDecoratedObjectException |
No instance was passed to the constructor and decoratedClass() returned null, so there is nothing to wrap. |
UndefinedMethodException |
A forwarded call targets a method that exists nowhere on the decorated object. |
Breaking change. These types previously surfaced as the SPL exceptions
LogicException(missing decorated object) andBadMethodCallException(undefined method). They now extend\ExceptionviaCacheDecoratorExceptionand are not instances of those SPL classes — update anycatch (LogicException ...)/catch (BadMethodCallException ...)blocks that relied on the old types.
Using with repositories
For repository-flavored use cases the package ships RepositoryCacheDecorator. It behaves exactly like CacheDecorator but reads its config from the repository_cache.* namespace instead of cache_decorator.*, so repository caches can be tuned independently of other decorators.
Install
Install with composer:
Publish whichever config you need (or both):
Environment variables:
| Config | Env var | Default |
|---|---|---|
cache_decorator.enabled |
CACHE_DECORATOR_ENABLED |
true |
cache_decorator.ttl |
CACHE_DECORATOR_TTL |
300 |
cache_decorator.use_tags |
CACHE_DECORATOR_TAGS |
true |
repository_cache.enabled |
REPOSITORY_CACHE |
true |
repository_cache.ttl |
REPOSITORY_CACHE_TTL |
300 |
repository_cache.use_tags |
REPOSITORY_CACHE_TAGS |
true |
Upgrading
From the previous 0.x line
A few breaking changes tightened the public contract:
- TTL bypass uses
null, notfalse. The "skip the cache" sentinel for$ttlis nownull. The property type isint|DateInterval|DateTimeInterface|null(defaultnull) andttl()has the same typed signature — replace anyprotected $ttl = false;withprotected $ttl = null;and anyttl(false)withttl(null). - The
voidsetters were dropped for a fluent grammar.setTtl()/setEnabled(bool)have been removed in favor of the chainablettl(),enable(), anddisable()methods (see Fluent configuration). ReplacesetTtl($n)withttl($n),setEnabled(true)withenable(), andsetEnabled(false)withdisable(). $tagsand$tag_cleanersare plain arrays. Both default to[](no longerarray|false). If the cache driver doesn't support tags (oruse_tagsis disabled in config), they are reset to[]rather thanfalse. Custom subclasses that initialized either property tofalseshould switch to[].- Falsy cached values round-trip correctly. Previously a method returning
0,'',[], orfalsewould look like a cache miss and be refetched on every call.getCache()now returns acacheMiss()sentinel (a sharedstdClass) on a true miss, and__call()compares with===— so falsy results are cached and served from cache as expected. If you wrote a custom method override withif (!$res)aroundgetCache(), switch it toif ($res === $this->cacheMiss())(see the override example above). - The
enabledflag now actually short-circuits caching. Setting$enabled = false(via the property,disable(), or{$config_key}.enabled = false) now causes__call()to forward straight to the decorated object, skipping cache reads, writes, and tag flushing.
From the repository-only version
The base class is now generic and the repository-specific glue has been removed in favor of the generic hooks:
- Replace
extends CacheDecoratorwithextends RepositoryCacheDecoratorif you want to keep reading config from therepository_cache.*namespace. - Rename your
repository()method todecoratedClass()(return type?string). The oldrepository()abstract has been removed. - In custom method overrides, replace
$this->repository->…with$this->decorated->…. The$this->repositoryalias has been removed. initRepository()has been removed; pass the instance via the constructor, or overridedecoratedClass().
From Laravel 5.x versions
This release targets Laravel 12 and 13 on PHP 8.2+. A few breaking changes:
- TTL semantics changed from minutes to seconds (matching Laravel 5.8+'s
Cache::putAPI). Update any$ttlproperty and therepository_cache.ttlconfig value accordingly — e.g.5(minutes) becomes300(seconds). $ttlmay now also be aDateIntervalorDateTimeInterface, in addition tointandnull(which bypasses the cache entirely).- Minimum PHP version is 8.2.
Tested with Laravel 12 and Laravel 13.
All versions of cache-decorator with dependencies
illuminate/config Version ~5.0
illuminate/support Version ~5.0
illuminate/log Version ~5.0