Eloquent ORM Cache
Whole Eloquent Model Cache Strategy
1. Cache array in the database
You can only store the eloquent array of data
in the cache to reduce
the stored memory usage
Can NOT use toArray()
method because the toArray()
method will change the casting data (e.g. AsCollection, AsArrayObject)
to the other data format. We need to keep the original data from the database, so we have to use the getAttributes()
to get the original data
public function putEloquentModelCache($Model, $cache_key, $minutes = null)
{
if ($Model instanceof Model) {
$id = $Model->getKey();
$cache_key = sprintf('Model:%s', $id);
// XXX $cache_data = $Model->toArray();
$cache_data = $Model->getAttributes();
Cache::put($cache_key, $cache_data, $minutes);
}
}
2. Get the eloquent model array cache
After you get the eloquent array of data
from the cache, we still want to manipulate these data as the Eloquent ORM. So we have to transform back
to the original eloquent model.
You can use the Eloquent newFromBuilder()
method to fill all these data back, to tell Eloquent these data are the original data from the database.
public function getEloquentModelCache(string $id, string $model_class_name)
{
$Model = null;
if (class_exists($model_class_name)) {
$TmpModel = new $model_class_name;
if ($TmpModel instanceof Model) {
$id = $TmpModel->getKeyName();
$cache_key = sprintf('Model:%s', $id);
$cache_data = Cache::get($cache_key);
if (!is_null($cache_data)) {
// The model exist then fill the model data from cache and sync back to the original attribute
// XXXX $Model = $TmpModel->fill($cache_data)->syncOriginal();
$Model = $TmpModel->newFromBuilder($cache_data);
}
}
}
return $Model;
}
If you DO NOT call the Eloquent newFromBuilder()
method, then the eloquent
will think all of these data are new data
. So when you execute the Eloquent update() or save()
methods, it will insert these data into the database.
So if you want to treat these data like they have already in the database when you execute the Eloquent update() or save()
methods. If you want them to update data
instead of insert data
, then you should call the Eloquent newFromBuilder()
method.
Other Eloquent Unique Key Cache Strategy
We always have the primary key
on the database table to let us find it. But sometimes we may have another unique table field
to let us query the data in different ways.
For instance, we have the primary key id
on the user table. But the email
and username
fields might be unique too. So we can find the right data from these 3 fields.
id | name | username | |
---|---|---|---|
u-xxxx | KJ | kj@example.com |
kj |
u-kkkk | Kay | kay@example.com |
kay |
u-jjjj | Jay | jay@example.com |
jay |
But if we want to cache the SAME user data in the 3 different keys. The cached user data will be duplicated
and hard to maintain
.
So the main goal is to store 1 user data on the cache, and the other cache data will reference back to the same data. If the cached user data is updated then everything will update.
1. Only cache the primary key for other unique keys
We only cache the primary key value
to the unique key
cache, so it will only store the single primary key id string
on the cache database
/**
* @param $Model
* @param $unique_key_field_name
* @param $minutes
* @return void
* @throws Exception
*/
public function putModelIdMappingCache($Model, $unique_key_field_name, $minutes = null)
{
if ($Model instanceof Model) {
// Model primary key value
$id = $Model->getKey();
// Model unique key value
$unique_key_field_value = $Model->{$unique_key_field_name};
$cache_key = sprintf('ModelUniqueKey:[%s:%s]', $unique_key_field_name, $unique_key_field_value);
// Store the primary key to the unique key cache
$cache_data = $id;
Cache::put($cache_key, $cache_data, $minutes);
}
}
2. Get the unique key cache and transform back
If we get the unique key
data from the cache, we will ONLY get the primary key value
for this eloquent model
Then we can use the original getEloquentModelCache()
method on the above to get the original eloquent model
/**
* @param $unique_key_field_name
* @param $unique_key_field_value
* @param $model_class_name
* @return Model|null
* @throws Exception
*/
public function getModelIdMappingCache($unique_key_field_name, $unique_key_field_value, $model_class_name)
{
$Model = null;
$cache_key = sprintf('ModelUniqueKey:[%s:%s]', $unique_key_field_name, $unique_key_field_value);
$id = Cache::get($cache_key);
if (!is_null($id)) {
// Call original model id cache method
$Model = $this->getEloquentModelCache($id, $model_class_name);
}
return $Model;
}