Blog Detail

03

Oct
Reduce Complexity Regarding Caching in Your Laravel Models cover image

arrow_back Reduce Complexity Regarding Caching in Your Laravel Models

Laravel Tagged Cache is a reasonably straightforward wrapper around the cache implementation to reduce complexity regarding caching in your Models. Note that this requires using a Cache implementation that supports tags. It is not supported if you are using a file, dynamodb or database, or cache drivers. My personal favorite cache store is Redis, but Memcached isn’t bad either.

Installation

Run this command in the terminal for installation purposes.

composer require brekitomasson/laravel-tagged-cache

Usage

In any one of your Laravel Models, just use the trait HasTaggedCache, and you will be able to create reliable caches that do not require a bunch of special handling regarding your cache keys. No more Cache::remember(‘user:’ . $this->id . ':displayname) or anything like that, as the heavy lifting is done inside the cache tags instead.

For example:

public function getDisplayNameAttribute(): string
{
  return $this->taggedCache()->remember('display-name', now()->addHour(), fn () => $this->nickname ?? $this->name ?? $this->email);
}

This method, if in your User model, will store the cache key display-name with the tags users and user:23 when used to get the display_name attribute for a user with the ID of 23 (or the value of whatever else that model’s database key is set to). It uses the name of the database table connected to the model as the generic users tag, then uses the Str::singular() method of that name as well as the value of id for the given instance of the model to generate user:23.

To set your own name instead of using the name of the database table, you can define a public string $cacheTagIdentifier = ‘things’ in your Model and the contents of that attribute will be used instead, storing the above example with things and thing:23. Note, however, that it has to be a string and that a plural noun is recommended so that Str::singular() can do its job.

You can also provide any amount of additional strings to the taggedCache() method, and those strings will be added to the list of tags. If, for example, you put something like this in your BlogEntry model:

public function getContent(): string
{
    return $this->taggedCache('markdown')->remember('content', now()->addHour(), fn () => $this->entry)
}

Getting and Caching a Single Attribute

Instead of having to write $this->taggedCache()->remember(‘name’, TimeSpan::ONE_DAY(), fn () => $this->name) there’s a simple helper function available if you’re only interested in a single attribute. The code above can be rewritten as $this->getCachedAttribute(‘name’). The cache is stored with a key named after the attribute for 24 hours.

Under the hood, it uses Laravel’s own getAttribute() method, which means you can use it to return relationships and attributes made available through Mutators and/or Accessor functions, and it takes your $casts into account.

Cache Invalidation

They say that there are only two hard things in Computer Science: cache invalidation and naming things. This is, of course, always going to be true when you’re storing things in your cache. Since this package makes it so much easier to cache things, however, you might be more willing to put things in your cache and run into some problems where the cache is returning values that are no longer correct. For that reason, I suggest you do the following:

If you are using HasTaggedCache in your User model, create a Listener for the UserHasLoggedIn event to ensure your users always log in with none of their values cached. It doesn’t have to be anything complicated, something like this is enough:

class ClearUserCacheOnLogin implements \Illuminate\Contracts\Queue\ShouldQueue
{
    public function handle(\App\Events\Auth\UserHasLoggedIn $userHasLoggedIn): void
    {
        $userHasLoggedIn->user->taggedCache()->flush();
    }
}

Also, for whatever models you’ve added HasTaggedCache to, it is not a bad idea to create an Observer for the model where you flush caches depending on what contents of the model have changed. For example, you might want to clear the Caches for BlogEntry if the title or content has changed, but not if blog_category_id has changed, since that value is never cached. Something like this in your BlogEntryObserver would do the trick:

    public function updated(BlogEntry $blogEntry): void
    {
        if ($blogEntry->isDirty(['title', 'content'])) {
            $blogEntry->taggedCache()->flush();        
        }
    }

For more details, please visit Github

Published at : 03-10-2022

Author : Rizwan Aslam
AUTHOR
Rizwan Aslam

I am a highly results-driven professional with 12+ years of collective experience in the grounds of web application development especially in laravel, native android application development in java, and desktop application development in the dot net framework. Now managing a team of expert developers at Codebrisk.

Launch your project

Launch project