eribloo / laravel-cache-objects
Strongly typed cache objects
Fund package maintenance!
EriBloo
Requires
- php: ^8.2
- illuminate/contracts: ^10.0||^11.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^9.0.0||^8.22.0
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- pestphp/pest-plugin-laravel: ^2.3
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-phpunit: ^1.3
- symplify/easy-coding-standard: ^12.3
README
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
Table of contents
Installation
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', ];
Usage
Creating
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.
CacheObject
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
Key interface is a wrapper for Stringable interface responsible for preparing key for storage. Currently 2 options exist.
StringKey
Basic key that accepts string.
public function key(): EriBloo\CacheObjects\ValueObjects\Keys\StringKey { return new StringKey(key: 'some-cache'); }
HashedKey
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', ); }
Time-to-live
Defined with Carbon\CarbonInterval
. Values that resolve to 0 or less seconds are considered to be stored forever.
Transformer
Transformers are classes responsible for modifying values before storage and after retrieval.
JsonTransformer
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, ); }
SerializeTransformer
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]); }
EncryptedTransformer
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, ); }
GuardTransformer
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, ); }
Traits
CacheObjectActions
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
Driver
This interface defines methods used for interacting with storage. Currently 1 class exists.
CacheDriver
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.
Events
Default driver dispatches events:
CacheObjectStored
When object is put in storage.
final class CacheObjectStored { public function __construct( public CacheObject $cacheObject, public mixed $originalValue, public string $transformedValue, ) {} }
CacheObjectRetrieved
When object is retrieved from storage.
final class CacheObjectRetrieved { public function __construct( public CacheObject $cacheObject, public string $originalValue, public mixed $transformedValue, ) {} }
CacheObjectMissed
When cache object retrieval misses.
final class CacheObjectMissed { public function __construct( public CacheObject $cacheObject, ) {} }
CacheObjectDeleted
When cache object is removed from storage.
final class CacheObjectDeleted { public function __construct( public CacheObject $cacheObject, ) {} }
Extending
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.
PHPStan
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.
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
All contributions are welcome.
Credits
License
The MIT License (MIT). Please see License File for more information.