Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cache Eloquent Relationship query

How can I cache this Eloquent query:

dd($user->roles);

Because above will somehow trigger the $user->roles() query I assume.

I have tried with this:

    public function roles() {
        return \Cache::remember('user_' . $this->id . '_roles', 10, function() {
            return $this->hasMany('App\Role');
        });
    }

But it does not work, because it has to return a array, not eloquent query.

Any suggestions?

like image 538
FooBar Avatar asked Mar 04 '15 00:03

FooBar


3 Answers

Here is my approach:

public function bookmarks(): HasMany
{
    return $this->hasMany(Bookmark::class);
}

protected function getBookmarksCacheKey(): string
{
    return sprintf('user-%d-bookmarks', $this->id);
}

public function clearBookmarksCache(): bool
{
    return Cache::forget($this->getBookmarksCacheKey());
}

public function getBookmarksAttribute(): Collection
{
    if ($this->relationLoaded('bookmarks')) {
        return $this->getRelationValue('bookmarks');
    }

    $bookmarks = Cache::rememberForever($this->getBookmarksCacheKey(), function () {
        return $this->getRelationValue('bookmarks');
    });

    $this->setRelation('bookmarks', $bookmarks);

    return $bookmarks;
}
like image 128
MingalevME Avatar answered Oct 19 '22 13:10

MingalevME


You can't store a relationship in the cache. You need to cache the actual data retrieved from the database. So you'll have something like this:

public function roles()
{
    return \Cache::remember('user_' . $this->id . '_roles', 10, function()
    {
        return $this->hasMany('App\Role')->get()->toArray();
    });
}

And now you have to access it as a method, not a property, because it's not returning a relation anymore (and Eloquent would throw an exception):

$user->roles();

Now you should get an array as you want.

like image 6
Bogdan Avatar answered Oct 19 '22 12:10

Bogdan


If you want to cache user together with its roles you can do it this way:

$user = User::find(1);
$user->load('roles');
Cache::put('users_'.$user->id, $user, 10);

I don't know why, but you need to use load here instead of with. If you used with you would get error that you cannot cache PDO instance.

like image 2
Marcin Nabiałek Avatar answered Oct 19 '22 14:10

Marcin Nabiałek