How to store and read data from cache in Laravel

Updated: January 16, 2024 By: Guest Contributor Post a comment

Introduction

Laravel provides a unified API for various caching systems. It supports popular caching backends like Memcached and Redis out of the box. Laravel uses the file cache driver by default, which stores cached objects in the file system. For larger applications, it is recommended to use an in-memory cache such as Memcached or Redis as they provide better performance.

Setup & Configuration

The first step is to configure the cache settings for your application, which can be done in the ‘config/cache.php’ file. You can set the default cache driver and configure the stores each driver utilizes.

'default' => env('CACHE_DRIVER', 'file'),

'stores' => [
    'file' => [
        'driver' => 'file',
        'path' => storage_path('framework/cache/data'),
    ],
    // More drivers...
],

Remember to set the .env file with the proper CACHE_DRIVER.

Storing Items in Cache

To store items in the cache, you can use the Cache::put method. You need to specify the key and value, and optionally the number of minutes until the item should be removed.

use Illuminate\Support\Facades\Cache; 

// Store an item for 10 minutes 
Cache::put('key', 'value', 10);

Checking For Item Existence

To determine if an item is in the cache, you can use the Cache::has method, which will return true or false:

if (Cache::has('key')) { 
   // The item exists in the cache... 
}

Reading Items From Cache

To retrieve an item from the cache, you can use the Cache::get method:

$value = Cache::get('key');

If the item does not exist in the cache, get will return null. You can also pass a second argument to specify a default value:

$value = Cache::get('key', 'default');

Incrementing / Decrementing Values

Laravel also provides methods for incrementing and decrementing integer values in the cache:

Cache::increment('key'); 
Cache::decrement('key');

Storing Items Indefinitely

Sometimes, you may wish to store an item in the cache indefinitely:

Cache::forever('key', 'value');

Retrieving & Storing

Sometimes you may wish to retrieve an item from the cache, but also store a default value if the requested item doesn’t exist.

$value = Cache::remember('key', $minutes, function () { 
   return DB::table(...)->get(); 
});

You may even store items forever:

$value = Cache::rememberForever('key', function () { 
   return DB::table(...)->get(); 
});

Deleting Items From the Cache

To remove an item from the cache, use the Cache::forget method:

Cache::forget('key');

Finally, you can flush the entire cache using the Cache::flush method, which will remove all items:

Cache::flush();

Database Cache Locks

Starting from Laravel 5.6, you can acquire locks on cache operations which can be useful to prevent race conditions:

if (Cache::lock('foo', 10)->get()) { 
  // Lock acquired for 10 seconds... 
  Cache::lock('foo')->release(); 
}

In this case, the second parameter of the get method is the number of seconds the lock should be held.

Tags & Tagged Cache

For the store supports tags, you can tag related items in the cache and then flush all caches that have assigned a given tag. This approach is particularly useful for categorizing related items.

Cache::tags(['people', 'artists'])->put('John', $john, $minutes); Cache::tags(['people'])->flush();

Advanced Example: Repository Pattern


Implementing the Repository Pattern in Laravel is a great way to abstract the caching layer and other data access logic. This pattern involves creating repository classes that centralize the logic for accessing data sources (like databases), and can be particularly useful for caching. Here’s an example of how you might implement this pattern:

Step 1: Create the Repository Interface

First, define an interface for your repository. This will ensure that any concrete repository classes implement specific methods.

namespace App\Repositories;

interface ProductRepositoryInterface
{
    public function getAll();

    public function findById($id);

    // Other necessary methods...
}

Step 2: Create the Concrete Repository

Next, create a concrete class that implements this interface. This is where you implement the caching logic.

namespace App\Repositories;

use App\Models\Product;
use Illuminate\Support\Facades\Cache;

class ProductRepository implements ProductRepositoryInterface
{
    protected $model;

    public function __construct(Product $product)
    {
        $this->model = $product;
    }

    public function getAll()
    {
        $cacheKey = 'products_all';
        return Cache::remember($cacheKey, 3600, function () {
            return $this->model->all();
        });
    }

    public function findById($id)
    {
        $cacheKey = 'product_'.$id;
        return Cache::remember($cacheKey, 3600, function () use ($id) {
            return $this->model->find($id);
        });
    }

    // Implement other methods...
}

Step 3: Bind the Interface to the Implementation

In a service provider (like AppServiceProvider), bind the interface to the concrete class.

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Repositories\ProductRepositoryInterface;
use App\Repositories\ProductRepository;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(ProductRepositoryInterface::class, ProductRepository::class);
    }

    // ...
}

Step 4: Use the Repository in Controllers

Finally, use the repository in your controllers by type-hinting the interface in the constructor.

namespace App\Http\Controllers;

use App\Repositories\ProductRepositoryInterface;

class ProductController extends Controller
{
    protected $productRepository;

    public function __construct(ProductRepositoryInterface $productRepository)
    {
        $this->productRepository = $productRepository;
    }

    public function index()
    {
        $products = $this->productRepository->getAll();
        return view('products.index', compact('products'));
    }

    // Other methods...
}

Explanation

  • Repository Interface: This defines the contract for the repository, ensuring consistency and predictability.
  • Concrete Repository: Implements the interface, encapsulating the data access logic and caching.
  • Service Provider: Binds the interface to a concrete implementation, allowing Laravel’s dependency injection to resolve the correct instance.
  • Controller: Uses the repository interface, making it easy to switch implementations or mock the repository in tests.

This pattern helps in keeping controllers slim and adhering to the Single Responsibility Principle. It also makes your application more maintainable and testable.

Conclusion

Caching is essential for optimizing performance in your Laravel applications. By effectively utilizing Laravel’s caching features, you can significantly reduce database load and improve application responsiveness.