Effortless and Enhanced Caching for Models and Classes
Laravel package that provides a streamlined and powerful solution for implementing caching within your application. This package simplifies the process of caching Eloquent models and other classes, ensuring improved performance and scalability for your Laravel application.
To install the package to your Laravel project via Composer:
composer require mahmoud217tr/cacheable
And once the installation is complete, the package will be ready up and ready for usage.
There is a lot of features and usecases we will summerize them with the following:
You can make the model cacheable by making it implement CacheableModel
interface and use the CacheableModelTrait
trait as the following example:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
}
Upon doing that your model will be using the
Cacheable Collection
as a collection which extends theEloquent Collection
, preserving the same logic and providing the model with caching features.
Making a model cacheable will provide you with caching features:
You can easily cache individual model records or collections of records using the cache
method as follows:
<?php
use App\Models\Post;
use Illuminate\Support\Facades\Cache;
use Mahmoud217TR\Cacheable\Facades;
# Caching the first post for 120 seconds
Post::first()->cache('first_post', 120);
# Caching published posts indefinitely
Post::whereNotNull('published_at')
->get()
->cache('published_posts');
# Retrieve cached data using the Cache facade
Cache::get('first_post');
Cache::get('published_posts');
# Or using the Cacheable facade
Cacheable::get('first_post');
Cacheable::get('published_posts');
Models can be auto-cached, meaning all model records will be cached and synchronized upon creation, updating, or deletion.
CAUTION: This behavior may be unsuitable for large models or models with frequent changes. Use it wisely based on your use case.
To enable auto-caching, override the isAutoCacheSyncEnabled
method in your model to return true
:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
}
Now, the auto-caching feature will be enabled, and all model records will be cached and updated automatically.
IMPORTANT: If you have modular Laravel application or you've changed your models default director, you'll need to do an extra step.
You can manage the cached models as follows:
<?php
use App\Models\Post;
# Get cached posts
$posts = Post::getCached();
# Update cached data manually
Post::syncCache();
# Flush cached data
Post::flushCache();
# Set cached data manually
Post::setCache(Post::limit(4)->get());
You can also control the auto-cached collection by overriding the getDataForCaching
method as it's default behaviour is to return the all
method result:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
public function scopePublished(Builder $query)
{
$query->whereNotNull('published_at');
}
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
protected static function getDataForCaching()
{
return static::published()
->latest()
->get();
}
}
And now only the published posts will cached by auto-caching feature and in order of the latest.
You can also control the TTL
of the cached data by overriding the getCacheTTL
method:
<?php
namespace App\Models;
use DateInterval;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
public function scopePublished(Builder $query)
{
$query->whereNotNull('published_at');
}
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
protected static function getDataForCaching()
{
return static::published()
->latest()
->get();
}
protected static function getCacheTTL(): null | int | DateInterval | DateTimeInterface
{
return 86400;
}
}
You can also utilize the cached records to be used in route model binding by simply be using the CachedRouteBinding
trait:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
use Mahmoud217TR\Cacheable\Models\Traits\CachedRouteBinding;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
use CachedRouteBinding;
public function scopePublished(Builder $query)
{
$query->whereNotNull('published_at');
}
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
protected static function getDataForCaching()
{
return static::published()
->latest()
->get();
}
}
Note: Modifying the auto-cached data by overriding the
getDataForCaching
method may result in404 Not Found
for non-cached model records. Solutions for this scenario will be discussed further.
You can change the cached data that is used for route model binding by overriding 2 methods:
- You should override the
shouldUseDifferentDataForBinding
method to returntrue
(which by default it returnsfalse
). - And you ou should also override the
getBindingData
method which represents the data collection to be cached (by default it returnsnull
).
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
use Mahmoud217TR\Cacheable\Models\Traits\CachedRouteBinding;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
use CachedRouteBinding;
public function scopePublished(Builder $query)
{
$query->whereNotNull('published_at');
}
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
protected static function getDataForCaching()
{
return static::published()
->latest()
->get();
}
protected static function shouldUseDifferentDataForBinding(): bool
{
return true;
}
protected static function getBindingData()
{
return static::all();
}
}
And now the data used for route model binding will be cached with a different key and have different values and will be synconized automatically.
When the usage of a different data for binding is enabled, you can control the TTL
of the route binding cache by overriding the getBindingCacheTTL
method:
<?php
namespace App\Models;
use DateInterval;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
use Mahmoud217TR\Cacheable\Models\Traits\CachedRouteBinding;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
use CachedRouteBinding;
public function scopePublished(Builder $query)
{
$query->whereNotNull('published_at');
}
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
protected static function getDataForCaching()
{
return static::published()
->latest()
->get();
}
protected static function shouldUseDifferentDataForBinding(): bool
{
return true;
}
protected static function getBindingData()
{
return static::all();
}
protected static function getBindingCacheTTL(): null | int| DateInterval | DateTimeInterface
{
return 3600;
}
}
You can also allow the model to use an alternative route binding method by overriding the shouldUseAlternativeRouteBinding
method to return true
:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
use Mahmoud217TR\Cacheable\Models\Traits\CachedRouteBinding;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
use CachedRouteBinding;
public function scopePublished(Builder $query)
{
$query->whereNotNull('published_at');
}
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
protected static function getDataForCaching()
{
return static::published()
->latest()
->get();
}
protected static function shouldUseDifferentDataForBinding(): bool
{
return true;
}
protected static function shouldUseDifferentDataForBinding(): bool
{
return true;
}
protected static function getBindingData()
{
return static::all();
}
protected static function shouldUseAlternativeRouteBinding(): bool
{
return true;
}
}
The default alternative route binding resolver is the resolveRouteBinding
method, which can be customized by overriding the alternativeRouteBinding
method:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mahmoud217TR\Cacheable\Models\Contracts\CacheableModel;
use Mahmoud217TR\Cacheable\Models\Traits\CacheableModelTrait;
use Mahmoud217TR\Cacheable\Models\Traits\CachedRouteBinding;
class Post extends Model implements CacheableModel
{
use CacheableModelTrait;
use CachedRouteBinding;
public function scopePublished(Builder $query)
{
$query->whereNotNull('published_at');
}
public static function isAutoCacheSyncEnabled(): bool
{
return true;
}
protected static function getDataForCaching()
{
return static::published()
->latest()
->get();
}
protected static function shouldUseDifferentDataForBinding(): bool
{
return true;
}
protected static function getBindingData()
{
return static::all();
}
protected static function shouldUseAlternativeRouteBinding(): bool
{
return true;
}
protected static function alternativeRouteBinding($value, $field = null)
{
return parent::customRouteBinding($value, $field);
}
}
You can easily make any thing cacheable by making it implements the Cacheable
interface and use the CacahableTrait
trait:
<?php
namespace App\Classes;
use Mahmoud217TR\Cacheable\Contracts\Cacheable;
use Mahmoud217TR\Cacheable\Traits\CacheableTrait;
class MyCustomClass implements Cacheable
{
use CacheableTrait;
protected string $customAttribute;
public function __construct(string $value)
{
$this->customAttribute = $value;
}
}
And you can use the cache function to store the object as follows:
<?php
use App\Classes\MyCustomClass;
$object = new MyCustomClass("data");
# Caching object indefinitely
$object->cache('cache_key_2');
# Caching object for 200 seconds
$object->cache('cache_key', 200);
You can also utilize the Cacheable
facade for some caching features, which has some drived features from the Cache
facade:
<?php
use App\Classes\MyCustomClass;
use App\Models\Post;
use Mahmoud217TR\Cacheable\Facades\Cacheable;
# --- Drived methods from the Cache facade ---
# Returns true if cached data was found
Cacheable::has('cache_key');
# Returns true if cached data was not found
Cacheable::missing('cache_key');
# Returns the cached data, if not found returns a default value
Cacheable::get('cache_key', 'default value');
# Caches data for with a given key for amount of time or indefinitely
Cacheable::put('cache_key', 'data', 20); # Caches data for 20 seconds
Cacheable::set('cache_key', 'data'); # Caches data indefinitely
# Invalidate cached data with a given key
Cacheable::forget('cache_key');
# --- New features ---
# Retrieves cached data by key
# Caches the value in the given value with the key if no data found
# You can also set a time to live for cache
Cacheable::cached('cache_key', 'data', 150);
# Returns true if the given model implements the CacheableModel interface
Cacheable::isCacheableModel(Post::class);
Cacheable::isCacheableModel(Post::first());
# Returns true if the given model implements the Cacheable interface
Cacheable::isCacheableClass(MyCustomClass::class);
Cacheable::isCacheableClass(new MyCustomClass('data'));
# Returns an array of the models that implements CacheableModel interface
Cacheable::getCacheableModels();
The package will give you a new helper functions:
- The
is_cacheable_model
helper function which checks if a mode or an instance of it implements theCacheableModel
interface. - The
is_cacheable_class
helper function which checks if a class or an instance of it implements theCacheable
interface. - The
cached
helper function which retrieves cached data of a given key, but if not found, it will cache the given value by the given key with a given time to live if provided.
<?php
use App\Classes\MyCustomClass;
use App\Models\Post;
# Returns true if the given model implements the CacheableModel interface
is_cacheable_model(Post::class);
is_cacheable_model(Post::first());
# Returns true if the given model implements the Cacheable interface
is_cacheable_class(MyCustomClass::class);
is_cacheable_class(new MyCustomClass('data'));
cached('cached_array_key', [1, 2, 3]) # Returns [1, 2, 3]
cached('cached_array_key') # Returns [1, 2, 3]
cached('cached_string_key', "Hello") # Returns "Hello"
cached('cached_string_key', "Ops") # Returns "Hello" because data was found
To customize the package caching behavior you can publish the configuration file by running the following command in your console to copy the config file to your application's config directory:
php artisan vendor:publish --provider="Mahmoud217TR\Cacheable\CacheableServiceProvider"
composer test
Please see CHANGELOG for more information on what has changed recently.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.