Skip to content

Instantly share code, notes, and snippets.

@jlem jlem/Member.php
Created Aug 25, 2015

Embed
What would you like to do?
Eloquent model caching
<?php
class Member extends Model implements CurrentMember
{
use ModelCache;
public function getLeaguePlayer(SectionInterface $section)
{
return $this->cache(function(SectionInterface $section) {
return $this->leaguePlayers()
->where('section_id', $section->getID())
->first();
});
}
}
<?php
trait ModelCache
{
protected $dataCache = [];
/**
* Gets the cached result by key, or executes the closure if cache key does not exist
* @param \Closure $closure
* @return mixed
*/
public function cache(\Closure $closure)
{
// This is so we know the name of the function call, and the arguments
// We want to md5 serialize these so the cache is unique to the arguments
$backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT,2)[1];
$key = $backtrace['function'];
$args = $backtrace['args'];
$key = $key . '.' . md5(serialize($args));
if (!array_key_exists($key, $this->dataCache)) {
$this->dataCache[$key] = call_user_func_array($closure, $args);
}
return $this->dataCache[$key];
}
/**
* Returns the entire cache
* @return array
*/
public function getCache()
{
return $this->dataCache;
}
}
@jlem

This comment has been minimized.

Copy link
Owner Author

jlem commented Aug 25, 2015

Note that this is not a cache as in a time-based cache - it's just a registry cache, so that subsequent calls to $member->getLeaguePlayer($section) in the remainder of the request cycle don't result in repeated queries.

This is identical in behavior to how Eloquent relations cache their results instead of repeating queries.

It would be great to have something more baked into Eloquent such that you don't have to do gross wrapping in a callback function all the time.

Perhaps an array property like:

$cacheable = [
    'getLeaguePlayers',
    'fooBarMethod'
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.