Laravel + Cache

If you’re with performance troubles in your website and want to let it a bit faster, one thing that we can do is utilize cache.

We can, for example, add a query to the database on the cache for an hour, and at this time, everyone who accesses your website will get the info from the cache instead of doing the same new query again and again.

Or, depending on the case, we can also put the whole view in the cache.

Today we’re going to use Memcached, but another cool stuff that you can read about is Redis. So, let’s move on.

To install Memcached:

sudo apt-get install -y memcached php5-memcached
sudo service apache2 restart

Open your .env file, where you config your environment, and change the CACHE_DRIVER from file to memcached.

CACHE_DRIVER=memcached

Let’s do a trick to check all the queries that your system are doing, so add at the top of your routes file:

\Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
var_dump($query->sql);
var_dump($query->time);
});

Now every time the system execute a query, it will appear in your view, and the time it took as well. That’s cool :)

One solution that we can adopt is to cache our queries or the JSON we got from some API as well. And it’s surprisingly easy in Laravel, just add in your Controller:

$posts = Cache::remember('posts', 60, function() {
return Post::all();
});
return $posts;

To understand it: ‘posts’ is the key used for caching and 60 is the time in minutes that it’ll live.

If you open this route in your browser, you will see that the query will appear, but it’s just for the first time, now refresh the page, and the query will disappear, that’s because you’re using the information at your cache.

And that’s it! As easy as pie. Just be care when you generate your keys, in the example above the system will look for a ‘posts’ key and get it if it exists, so to another thing you need to add a different key. To cache a single post you can use the slug or the id to generate your cache key, like posts_slug or posts_id.

Another solution is to put the whole view in the cache. To do it let’s create a middleware that will be responsible to config it all, so:

php artisan make:middleware CacheMiddleware

Open the file at \app\Http\Middleware\CacheMiddleware.php and replace to:

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Cache;
class CacheMiddleware
{
//Fetch
public function handle($request, Closure $next)
{
$key = $this->makeCacheKey($request->url());
        if (Cache::has($key)) {
return response(Cache::get($key));
}
        return $next($request);
}
    //Put
public function terminate($request, $response)
{
$key = $this->makeCacheKey($request->url());
        if (! Cache::has($key)) {
Cache::put($key, $response->getContent(), env('CACHE_TIME', 60));
}
}
    //Unique Key
protected function makeCacheKey($url)
{
return 'route_' . str_slug($url);
}
}

Resuming, the handle() is like the “before” and the terminate() is like the “after”. So when you access the page, the system will check if this view is in the cache, and if it’s true, show the value in the cache. But if it’s false, displays the view ordinarily and then put it all in the cache.

Let’s turn it on. Open the file at \app\Http\Kernel.php and then you can do something like adding our new middleware at the $routeMiddleware[], then you need to tell which routes will use it. Let’s do that:

'cache' => \App\Http\Middleware\CacheMiddleware::class,

And again at your routes file, create a new group using the cache middleware:

Route::group(['middleware' => 'cache'], function() {
// Your routes here
});

Open your .env file again and put it on a new line:

CACHE_TIME=60

We created that environment config in our Middleware, do you remember?

And now, it’s done! Open your browser and you’ll see the query just for the first time and when you refresh the page it doesn’t appear anymore. It’s working :)

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.