Jan 06, 2014
Table of contents:
Cache is probably one of the most underestimated components of the modern web application stack. Cache is basically a persistence layer between your website and your database. Database queries can be slow, especially when you have lots of traffic. The cache layer basically acts as a middle ground to store data that has not been changed between requests. Retrieving data from cache rather than a database is much quicker and will take a lot of stress off your database.
The thing about cache is, at the very beginning you are probably not going to need it. When there is just you and a handful of other users using your application you are probably not going to even notice the difference.
However, if you neglect to add cache support in the beginning, it’s going to come back and bite you when you do start to get traction. Last week I looked at Eager Loading in Laravel 4. Cache is basically the second step towards ensuring that your application will be able to handle the influx of traffic you will receive when your website starts getting noticed.
In this tutorial I’m going to walk you through using cache in Laravel 4. Cribbb is going to be cached to within an inch of it’s life, so hopefully this post will act as a foundation post for future tutorials on efficient data storage and retrieval.
So as I mentioned above, cache is basically a middle ground between your application and your database. When you have data that does not change in between page requests it’s a good idea to put it in the cache rather than asking the database each time.
A classic example of when to use cache is in blogging software. When you publish a new post, the contents of that post is likely not going to change. This means there is no point in asking the database for a fresh copy every time the post is requested. Instead if you put the blog post in the cache, the database is only ever asked for the post once. If at some point in the future you want to update the post, you can simple drop the post from the cache and update it with the new version.
One of the most popular caching systems is Memcached which is used by many of the most trafficked websites on the Internet. A while ago I actually wrote a post on Getting started with Memcached, so if you want to see how Memcached works outside of the world of Laravel, you should check out that post too.
One of the best things about Laravel 4 is it can handle caching for us right out of the box. Laravel actually allows you to use multiple different cache systems all through a unified API. This is really nice because it means if you switch from one system to another you wouldn’t have to change all of your code.
You will find the cache configuration settings under app/config/cache.php
. As you can see by default Laravel will use the file
storage system for your cache. This is fine for testing or development, but for production you are really going to want to use Memcached.
Using cache can seem difficult when you are first getting your head around how to use it in building web applications, but in fact it is really quite easy. You are either putting stuff in, getting stuff out, or asking if something currently exists in the cache. It’s really not much more complicated than that.
There are two ways in which you can add something to the cache in Laravel 4.
Firstly, you can use the put()
method:
Cache::put("post_123", $post, 60);
Here I’m putting the $post
object in the cache for 60 minutes. The post_123
is the unique key that I want to associate with this post. In this example I would simply be joining the string post_
with the $id
of the post. You basically just need to create a unique key, and I found that joining the id with a string of the item type is the most common approach.
Secondly, you can store an item if it doesn’t already exist:
Cache::add("post_123", $post, 60);
If you look at the source code you will see that the difference between the put
method and the add
method is, the add
method will only store the item in the cache if the key does not already exist. If the key does exist the method will return false, but if the item is successfully stored in the cache the method will return true.
If you want to store something in the cache permanently, you can use the forever()
method:
Cache::forever("post_123", $post);
To retrieve stuff from the cache, you can simply use the get()
method:
$post = Cache::get("post_123");
You can also provide a default value if the key you are looking for does not exist:
$post = Cache::get("post_123", $draft);
To remove an item from the cache, you can use the forget()
method:
Cache::forget("post_123");
Finally to check if something exists in the cache, you can use the has()
method:
if (Cache::has("post_123")) {
return Cache::get("post_123");
}
As you can probably guess, the has
method will return either true
or false
.
Now that you’ve got the basic storage and retrieval methods down, we’ll look at some more advanced things you can do.
In order to make your code more concise, it is possible to retrieve and store a default in one method. This allows you to retrieve what you want if it is available, or store it if it is not. This reduces a lot of boiler plate code for adding, checking and retrieving because you can do it all in one method.
Say for example we wanted to store all of our posts in the cache. We could so something like this:
$posts = Cache::remember("posts", 60, function () {
return DB::table("posts")->get();
});
In the code above I’m requesting the posts
key from the cache, but if it is not available the closure will insert the results from the DB::table('posts')->get()
query. The next time you ask for the posts
key, the query will not be run.
If you don’t want to provide a time constraint on how long the cache will store the data, you can use the rememberForever()
method like this:
$posts = Cache::rememberForever("posts", function () {
return DB::table("posts")->get();
});
Cache is a useful thing to store counts as it is quite redundant to hit a database every time you want to increase or decrease a counter. This is even more important when you are running an active site that has constant rising and falling counts.
Fortunately Laravel provides increment()
and decrement()
methods to do just that.
To increment:
// Increase by 1
Cache::increment("user_1_karma");
// Increase by 10
Cache::increment("user_1_karma", 10);
To decrement:
// Decrease by 1
Cache::decrement("user_1_karma");
// Decrease by 10
Cache::decrement("user_1_karma", 10);
Note: You can’t use the increment and decrement methods with the file
or database
caching systems.
Laravel also allows you to group data together so that you can flush sections of your cache based upon a tag. This is useful because often you will need to invalidate a whole section of your cache rather than a single item. Having to cycle through all of the related items in the cache to invalidate them would be a right nightmare, so by tagging them, we can easily remove whole sections of the cache in one easy to use command.
Again as I mentioned with increment
and decrement
you can’t use cache tags with the file
or database
caching systems. This means if you want to use the cache tags functionality you will need to have Memcached running in your local environment.
When you want to tag an item in the cache, it is basically the same as adding something in as normal except you must use the tags
method and pass the tags that you want to tag this item with. You can then chain the normal cache method straight after the tags
method, for example:
Cache::tags("client")->put("client_123", $client, $minutes);
In the example above, I’m adding a client to the cache and tagging it with the client tag. This means at any point in the future when I want to remove all client data from the cache I will be able to remove everything that has the tag of client
.
The beautiful thing about tags is, you can add multiple tags for each item. To add multiple tags, either pass an array or multiple tags to the tags
method:
// Using multiple arguments
Cache::tags("client", "client_123")->put("client_123", $client, $minutes);
// Using an array
Cache::tags(["contacts", "client_123"])->put("contact_456", $contact, $minutes);
As you can see in the example above, you can either use an array of tags or simply pass a list of tags separated by a comma.
Notice how we can chain the put
method after the tags
method? This allows you to use the other storage methods in much the same way.
To get data out of the tagged cache, you need to supply the list of tags and use the get
method:
// With a single tag
Cache::tags("client")->get("client_123");
// With multiple tags
Cache::tags("contacts", "client_123")->get("contact_456");
And finally flushing is where tagging your caches really comes into it’s own. You can now flush whole sections of your cache in one movement.
For example, say you wanted to flush all of the client’s in your application. You could run:
Cache::tags("client")->flush();
Or perhaps you only wanted to flush all the data that is associated with a particular client, you could run:
Cache::tags("client_123")->flush();
The first command would flush all of the clients, but not the contacts, whereas the second command would flush all of the data associated with client_123
but not all of the client and not all of the contacts. Pretty cool huh?
And of course you can supply many tags in one command using either multiple arguments or an array of arguments:
// Using multiple arguments
Cache::tags("client", "contact")->flush();
// Using an array
Cache::tags(["client", "contact"])->flush();
So that is how to use cache in Laravel 4. If you read my post on Getting started with Memcached you will appreciate how much of the heavy lifting Laravel is able to abstract away from us as developers. Laravel is also able to abstract the actual storage of cache using the repository pattern. This means should we want to change from Memcached to Redis in the future, we won’t have to change any of our code.
As hopefully I’ve shown above, Laravel provides us with a very clean and intuitive API for working with cache. However, much of the actual implementation of cache within your application is up to you. If you are new to cache it can be tempting to just start using it in your controllers, but as you know, this is a really bad practice.
So, over the next couple of weeks I will be looking at how to structure well designed and maintainable applications. If you find yourself asking, “where do I put this?” or “how does this fit into my application?”, hopefully the next couple of posts will answer a lot of these questions.
This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.