Introducing Laravel package that simplifies cache management by allowing you to encapsulate all details in one place. Improve your application cache maintanance with less raw strings and static typing.
/**
* @implements CacheObject<CarbonInterface>
*
* @method static self make(User $user)
*/
final readonly class SomeUserCache implements CacheObject
{
/** @use CacheObjectActions<CarbonInterface> */
use CacheObjectActions;
public function __construct(
public User $user,
) {}
public function key(): StringKey
{
$id = $this->user->getKey();
return new StringKey("some-cache:$id");
}
public function ttl(): CarbonInterval
{
return CarbonInterval::minutes(15);
}
/**
* @return SerializeTransformer<CarbonInterface>
*/
public function transformer(): SerializeTransformer
{
return new SerializeTransformer();
}
}
You can later use this object to interract with cache:
$user = User::findOrFail(1);
$key = SomeUserCache::make($user)->store(now()); // 'some-cache:1'
$date = SomeUserCache::make($user)->retrieve(); // App\Support\Carbon object
$bool = SomeUserCache::make($user)->delete(); // true
You can install the package via composer:
composer require eribloo/laravel-cache-objects
You can publish the config file with:
php artisan vendor:publish --tag="cache-objects-config"
This is the contents of the published config file:
return [
'namespace' => 'App\Cache',
];
You can create basic Cache Object by running Artisan Command:
php artisan make:cache-object SomeCacheObject
this will create class implementing EriBloo\CacheObjects\Contracts\CacheObject
in namespace specified in config with some defaults for you to configure.
EriBloo\CacheObjects\Contracts\CacheObject
interface requires you to implement 3 methods:
public function key(): EriBloo\CacheObjects\Contracts\Key;
public function ttl(): Carbon\CarbonInterval;
public function transformer(): EriBloo\CacheObjects\Contracts\Transformer;
Key interface is a wrapper for Stringable interface responsible for preparing key for storage. Currently 2 options exist.
Basic key that accepts string.
public function key(): EriBloo\CacheObjects\ValueObjects\Keys\StringKey
{
return new StringKey(key: 'some-cache');
}
Decorator for other keys that returns hashes key before storage. Accepts optional algorithm in constructor (sha256
by default).
public function key(): EriBloo\CacheObjects\ValueObjects\Keys\HashedKey
{
return new HashedKey(
key: new StringKey('some-cache'),
algo: 'md5',
);
}
Defined with Carbon\CarbonInterval
. Values that resolve to 0 or less seconds are considered to be stored forever.
Transformers are classes responsible for modifying values before storage and after retrieval.
Uses json_encode
on save and json_decode
on load. Accepts optional flags and depth in constructor.
public function transformer(): EriBloo\CacheObjects\ValueObjects\Values\JsonTransformer
{
return new JsonTransformer(
loadFlags: JSON_INVALID_UTF8_SUBSTITUTE,
saveFlags: JSON_UNESCAPED_UNICODE,
depth: 256,
);
}
Transformer that uses PHP serialize
on save and unserialize
on load. Accepts optional class-string[]|bool
in constructor to specify classes allowed for deserialization.
public function transformer(): EriBloo\CacheObjects\ValueObjects\Values\SerializeTransformer
{
return new SerializeTransformer(allowedClasses: [SomeClass::class]);
}
Decorator for other transformer that uses Crypt::encryptString
on save and Crypt::decryptString
on load.
public function transformer(): EriBloo\CacheObjects\ValueObjects\Values\EncryptedTransformer
{
return new EncryptedTransformer(
transformer: new SerializeTransformer,
);
}
Proxy for other transformer that doesn't modify values, but instead validates them before storage or after retrieval. This class accepts up to 2 closures that should throw an Exception when provided value is invalid.
public function transformer(): EriBloo\CacheObjects\ValueObjects\Values\GuardTransformer
{
return new GuardTransformer(
transformer: new EncryptedTransformer(new SerializeTransformer),
onSaveGuard: function (CarbonInterface $value) {
if ($value->isPast()) {
throw new UnexpectedValueException;
}
},
onLoadGuard: null,
);
}
Optional (but helpful) trait that adds usage methods:
public static function make(): static; // easier creation
public function store(mixed $value): string; // put into storage, returns key stored in cache
public function retrieve(): mixed; // get from storage
public function delete(): bool; // remove from storage
protected function resolveDriver(): EriBloo\CacheObjects\Contracts\Driver; // resolves to default driver from Service Provider, more below
This interface defines methods used for interacting with storage. Currently 1 class exists.
This class is a default driver that accepts an instance of Illuminate\Contracts\Cache\Store
. Binding defined in Service Provider resolves this to your default cache storage.
Default driver dispatches events:
When object is put in storage.
final class CacheObjectStored
{
public function __construct(
public CacheObject $cacheObject,
public mixed $originalValue,
public string $transformedValue,
) {}
}
When object is retrieved from storage.
final class CacheObjectRetrieved
{
public function __construct(
public CacheObject $cacheObject,
public string $originalValue,
public mixed $transformedValue,
) {}
}
When cache object retrieval misses.
final class CacheObjectMissed
{
public function __construct(
public CacheObject $cacheObject,
) {}
}
When cache object is removed from storage.
final class CacheObjectDeleted
{
public function __construct(
public CacheObject $cacheObject,
) {}
}
I created this package with ease of configuration in mind so you can easly create Key
, Transformer
or Driver
that will suit your needs. Additionally if you have any ideas of classes that could be incorporated into main package feel free to open an Issue or Pull Request.
While I omited most of static typing in examples above for clarity, this package is developed with level 8 of PHPStan and parts of code that are working with mixed
values (transformers, cache object interface and cache object action) are built with generics.
composer test
Please see CHANGELOG for more information on what has changed recently.
All contributions are welcome.
The MIT License (MIT). Please see License File for more information.