Laravel Caching Strategies Every Developer Wishes They Knew Sooner
Tags: webdev, laravel, tutorial, codenewbie
Published: 2023-08-02 12:00:00

Caching is essential for fast and efficient websites. Implementing the right caching strategy from the start is crucial to avoid slow APIs and page load times that can harm your SEO, user engagement, and conversion rates.

There are several cache strategies available, and you can even create a custom strategy to fit your needs. Here are some popular caching strategies that you can implement in your Laravel project.

## **Laravel Caching Strategies**

### **writeThrough**

In the **writeThrough** strategy, the cache server sits between the requests and the database server, making every **write** operation go through the cache server before going to the Database Server. Thus, the **writeThrough** caching strategy is similar to the **readThrough** strategy.

You can implement this strategy with the Laravel cache with the following code:

```php
public function writeThrough($key, $data, $minutes) {
    $cacheData = Cache::put($key, $data, $minutes)

    // Database Server is called from(after) the Cache Server.
    $this->storeToDB($cachedData)
    return $cacheData
}

private function storeToDB($data){
    Database::create($data)
    return true
}
```

### **writeBack (writeBehind)**

This strategy is a more advanced way of implementing the **writeThrough** strategy by adding writing operations delays.

You can also call this the **writeBehind** strategy because of the delay in time applied to the cache server before writing the data to the database server.

You can implement this strategy with the Laravel cache with the following code:

```php
$durationToFlush = 1; // (in minute)
 $tempDataToFlush = [];

  public function writeBack($key, $data, $minutes){
    return $this->writeThrough($key, $data, $minutes);
  }

  public function writeThrough($key, $data, $minutes) {
      $cacheData = Cache::put($key, $data, $minutes);
      $this->storeForUpdates($cacheData);
      return $cacheData;
  }

// Stores new data to temp Array for updating
  private function storeForUpdates($data){
    $tempData = {};
    $tempData['duration'] = this.getMinutesInMilli();
    $tempData['data'] = data;
    array_push($tempDataToFlush, data);
  }

// Converts minutes to millisecond
private function getMinutesInMilli(){
  $currentDate = now();
  $futureDate = Carbon(Carbon::now()->timestamp + $this->durationToFlush * 60000)
  return $futureDate->timestamp
}

// Calls to update the Database Server.
public function updateDatabaseServer(){
  if($this->tempDataToFlush){
    foreach($this->tempDataToFlush as $index => $obj){
      if($obj->duration timestamp){
        if(Database::create($obj->data)){
            array_splice($this->tempDataToFlush, $index, 1);
        }
      }
    }
  }
}
```

The **writeBack** method calls to the **writeThrough** method, which stores the data to the cache server and a temporary array to be pushed later to the database server using the **updateDatabaseServer** method. You can set up a [CronJob](https://masteringbackend.com/posts/laravel-cron-the-definitive-guide) to update the database server every five minutes.

### **writeAround**

This strategy allows all the **write** operations to go directly to the database server without updating the cache server — only during the **read** operations is the cache server updated.

Assuming a user wants to create a new **Article**, the **Article** stores directly to the database server. When the user wants to read the **Article**‘s content for the first time, the **Article** is retrieved from the database server and updates the cache server for subsequent requests.

You can implement this strategy with the Laravel cache with the following code:

```php
public function writeAround($data) {
    $storedData = Database::create($data);
    return $storedData;
}

public function readOperation($key, $minutes){
    $cacheData = Cache::remember($key, $minutes, function() {
      return Article::all();
    })
    return $cacheData;
}
```

### **Cache Aside (Lazy Loading)**

The database is sitting aside in this strategy, and the application requests data from the cache server first. Then, if there’s a hit (found), the data is returned to the client. Otherwise, if there’s a miss (not found), the database server requests the data and updates the cache server for subsequent requests.

You can implement this strategy with the Laravel cache with the following code:

```php
public function lazyLoadingStrategy($key, $minutes, $callback) {
  if (Cache::has($key)) {
      $data = Cache::get($key);
      return $data;
  } else {
      // Database Server is called outside the Cache Server.
      $data = $callback();
      Cache::set($key, $data, $minutes);
      return $data;
  }
}
```

The code above shows the implementation of the cache Aside Strategy, which is equivalent to implementing the **Cache::remember** method.

### **Read Through**

This strategy is the direct opposite of the cache Aside Strategy. In this strategy, the cache Server sits between the Client Request and the Database Server.

Requests go directly to the cache server, and the cache server is responsible for retrieving the data from the [database server](https://kinsta.com/blog/install-php/) if not found in the cache server.

You can implement this strategy with the Laravel cache with the following code:

```php
public function readThrough($key, $minutes) {
      $data = Cache::find($key, $minutes);
      return $data;
}

private function find($key, $minutes){
    if(Cache::has($key);){
      return Cache::get($key);
    }

    // Database Server is called from the Cache Server.
    $DBdata = Database::find($key);
    Cache:put($key, $DBdata, $minutes);
    return $DBdata;
}
```

There you have it! We’ve now discussed a few popular caching strategies for your next Laravel application. Remember, you can even use a custom caching strategy that best suits your project requirements.

## **Caching the UI Part of a Laravel App**

Caching the UI of our Laravel App is a concept known as Full Page cache FPC. The term refers to the process of caching the HTML response from an application.

It’s excellent for applications where the dynamic HTML data doesn’t change frequently. You can cache the HTML response for a faster overall response and rendering of the HTML.

We can implement FPC with the following line of code:

```php
class ArticlesController extends Controller {
    public function index() {
        if ( Cache::has('articles_index') ) {
            return Cache::get('articles_index');
        } else {
            $news = News::all();
            $cachedData = view('articles.index')->with('articles', $news)->render();
            Cache::put('articles_index', $cachedData);                                         
            return $cachedData;           
        }  
    }
}
```

At first glance, you might have noticed that we check if that **articles\_index** page already exists in our cache server. Then we return the page by rendering it with Laravel’s **view()** and **render()** methods.

Otherwise, we render the page and store the output in our cache server for subsequent requests before returning the rendered page to the browser.

## **Build a Laravel App**

Now we’re going to apply what we’ve learned so far by creating a new Laravel project and implementing Laravel cache.

If you haven’t used Laravel, you can read through [what Laravel is](https://kinsta.com/knowledgebase/what-is-laravel/) and peek at our list of [excellent Laravel tutorials](https://kinsta.com/blog/laravel-tutorial/) to get started.

### **Setting Up Laravel**

First, we’re going to create a fresh Laravel instance using the below command. You can look up the official documentation for more.

Open your console and navigate to where you store your PHP projects before running the commands below. Make sure to have [Composer](https://getcomposer.org/) installed and configured correctly.

```bash
composer create-project laravel/laravel fast-blog-app

// Change directory to current Laravel installation
cd fast-blog-app

// Start Laravel development server.
php artisan serve
```

### **Configuring and Seeding the Database**

Next, we will set up our database, create a new **Article** model, and seed 500 fake data points for testing.

Open your [database client](https://kinsta.com/blog/adminer/) and create a new database. We’ll do the same with the name **fast\_blog\_app\_db** and then fill up our **.env** file with the database credentials:

```bash
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=fast_blog_app_db
DB_USERNAME=//DB USERNAME HERE
DB_PASSWORD=//DB PASSWORD HERE
```

Next, we’ll run the following command to create the migration and the **Article** model simultaneously:

```bash
php artisan make:model Article -m
```

Open the newly created migration found `database/migrations/xxx-create-articles-xxx.php` and paste in the following code:

```php
id();
            $table->string('title');
            $table->text('description');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}
```

Next, run the command below to create a new seeder:

```bash
php artisan make:seeder ArticleSeeder
```

Open the newly created seeder file found in `database/seeders/ArticleSeeder.php` and paste in the following code:

```php
count(500)->create();
    }
}
```

Open the **DatabaseSeeder.php** file in the same directory and add the following code:

```php
call(ArticleSeeder::class);
    }
}
```

Next, run the command below to create a new factory:

```bash
php artisan make:factory ArticleFactory
```

Open the newly built factory file found in `database/factories/ArticleFactory.php` and paste in the following code:

```php
 $this->faker->text(),
            'description' => $this->faker->paragraph(20)
        ];
    }
}
```

Now, run the command below to migrate our newly created schema and also seed our fake data for testing:

```bash
php artisan migrate --seed
```

### **Creating the Article Controller**

Next, we will create our controller and set up our routes to handle our request and retrieve data using the above model.

Run the following command to create a new **ArticlesController** inside the `app/Http/Controllers` folder:

```bash
php artisan make:controller ArticlesController --resource
```

Open the file and add the following code to the class:

```php
// Returns all 500 articles with Caching
public function index() {
  return Cache::remember('articles', 60, function () {
      return Article::all();
  });
}

// Returns all 500 without Caching 
public function allWithoutCache() {
  return Article::all();
}
```

After that, open the **api.php** file found inside the `routes/` folder and paste in the following code to create an endpoint we can call to retrieve our data:

```php
Route::get('/articles', 'ArticlesController@index');

Route::get('/articles/withoutcache', 'ArticlesController@allWithoutcache');
```

### **Testing the Performance**

Lastly, we will [test the performance](https://kinsta.com/blog/application-performance-monitoring/) of our app’s response with or without the implementation of the Laravel cache.

This screenshot shows the response time of the API with cache implemented:


![Laravel API response time with cache](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/07rnfidhxrrv4bahxxqi.png)


Laravel API response time with cache.

The following screenshot shows the response time of the API without cache implemented — note that the response time has increased over the cached instance by over **5,000%**:


![Laravel API response time without cache](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uzdcf33hx0i4zyig9fer.png)


Laravel API response time without cache.

---

For more Laravel, explore [the best laravel tutorials](https://kinsta.com/blog/laravel-tutorial/). Whether you’re a beginner or an advanced Laravel developer, there’s something for everyone in there.

Got questions about Laravel caching? Just drop a comment below!