Laravel 10 - Laravel Cache Redis And File Store Tutorial With Example.

Hello Artisan, today I'll show you example of make a Laravel cache class for storing data in either a Redis server or files. Laravel offers robust APIs for caching, so let's dive in and begin.

To enhance your application's performance and reduce hosting costs, Laravel provides a Cache API. It allows you to store the results of time-consuming or CPU-intensive tasks, such as retrieving data from a database or processing information before responding. By saving these results in files, in-memory data stores, or databases, Laravel supports multiple cache services that offer quick data retrieval, ultimately boosting the speed of your applications.

Table of Contents

  1. Understanding cache
  2. Configuring cache driver
  3. File
  4. Redis
  5. Laravel cache helper class
  6. Using Cacher class with controllers

Understanding cache

When we want information about a product from the database, we can first check if we've already fetched it before. If not, we retrieve the data by its unique ID and store it in a cache. The cache works like a dictionary, where each piece of data has a specific key. If we ask for the same product data again, we check the cache first using the unique key. The key is crucial because it ensures we don't mix up or overwrite the existing data in the cache.

//store data
Cache::put('key', 'value');
Cache::put('product_'.$id, $product);

//retrieve data
$value = Cache::get('key');
$product= Cache::get(product_'.$id);

Configuring cache driver

In the .env file, set the CACHE_DRIVER variable to choose the default cache driver, which is configured in the config\cache.php file under the 'stores' array. For this example, we'll use the file and Redis drivers.

File

In Laravel, cached data is stored in files on the local disk using the file system. The path for saving the cache is "framework/cache/data." This method is cost-effective, requiring no additional requirements or a new host. While it's slower than Redis, for large datasets like articles, they perform similarly. It's well-suited for small and medium traffic, and it can handle high traffic too, but for optimal results, Redis is recommended.

Redis

Before we begin, make sure to install Redis on your machine. It's an in-memory key-value database, cache, and message broker. You can find installation instructions in the Redis documentation. If you prefer, you can skip this step and use file storage only.

Install the predis/predis package, a versatile Redis client for PHP and Laravel with rich features.

composer require predis/predis

Ensure that the Redis client configuration in config\database.php is set to 'predis'. I'm using Windows 10 with WSL2 and Ubuntu 22; that's my setup.

'redis' => [
       
        'client' => env('REDIS_CLIENT', 'predis'),

        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'redis'),
            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
        ],

        'default' => [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'username' => env('REDIS_USERNAME'),
            'password' => env('REDIS_PASSWORD'),
            'port' => env('REDIS_PORT', '6379'),
            'database' => env('REDIS_DB', '0'),
        ],

        'cache' => [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'username' => env('REDIS_USERNAME'),
            'password' => env('REDIS_PASSWORD'),
            'port' => env('REDIS_PORT', '6379'),
            'database' => env('REDIS_CACHE_DB', '1'),
        ],

    ],

Laravel cache helper class

Create a cache helper named Cacher in the app\Helpers folder. This helper can work with multiple stores and will be used in the controller later.

app\Helpers\Cacher.php
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\Cache;

class Cacher{
    public function __construct( public string $store = 'file'){}
  
   
    public function setCached($key,$value){

        $cachedData = Cache::store($this->store)->put($key,$value);
  
    }

  public function getCached($key){

    $cachedData =   Cache::store($this->store)->get($key);
        if($cachedData){
            return json_decode($cachedData);
        }
        
    }

    public function removeCached($key){

        Cache::store($this->store)->forget($key);
  
        
    }
}

In the constructor, we use $store to choose the cache storage, opting for either a file or Redis. We have methods like setCached to store data in the chosen storage with a specific key-value pair, getCached to fetch data based on a key, and removeCached to delete data from the cache storage.

Using Cacher class with controllers

<?php

namespace App\Http\Controllers\Admin;

use App\Helpers\Cacher;

class ProductController extends Controller
{
 
//we call the cacher with the store name file or redis
    private  $cacher;
    public function __construct(){
     $this->cacher =  new Cacher('file');
    }


   public function store(ProductStoreRequest $request)
    {
         $data = $request->validated();
         $product = new ProductResource(Product::create($data));
         $this->cacher->setCached('product_'.$product->id, $product->toJson()); 
         return response()->json($product, 200);
    }



    public function show(Request $request, $id)
    {
        

        $cachedData = $this->cacher->getCached('product_'.$id);
        if($cachedData){
        $product = $cachedData;
        }else{
        $product = new ProductResource(Product::find($id));
        $this->cacher->setCached('product_'.$id,  $product->toJson());
        }
        
        return response()->json($product, 200);
         
    }


   public function update(ProductUpdateRequest $request, Product $product)
    {
        $data = $request->validated();
        $product->update($data);
        $product->refresh();
        
        $success['data'] =  new ProductResource($product);
      $this->cacher->setCached('product_'.$product->id, $success['data']->toJson()); 
      $success['success'] = true;

        return response()->json($success, 200);
    }


    public function destroy(ProductDeleteRequest $request,Product $product)
    {
      $this->cacher->removeCached('product_'.$product->id);
      $product->delete(); 
    }

}

In the constructor, we set the file as our cache driver. If you prefer not to use a file and want to use Redis instead, you can make that change, and everything will still function. In the example above, our cache class was used in many instances. When saving data, you can skip creating a new ProductResource instance with new ProductResource($product) and use the collection directly. When adding a new product, we generate a cache for it. When updating, we simply replace the existing cache. For the 'show' function, we first look for a cached version. If not present, we fetch it from the database and then generate a new cache for it.

That's it for today. I hope it'll be helpful in upcoming project.