Search code examples
phplaravellaravel-cache

How to create a cache that stores an array and can be pushed in Laravel


The code should do the following:

  1. If the cache is empty, get from database
  2. Create order
  3. Push order to cache and save it in database
  4. Redirect user

How can I keep the cache sync with database to avoid errors?

code

$maxLock = 60;

$lock = Cache::lock("cacheLock", $maxLock);
$lock->block($maxLock);

$cachedIds = Cache::get("cachedIds");

if (empty($cachedIds)) {
  $cachedIds = $product
    ->orders()
    ->whereNot('status', 'expired')
    ->implode('id', ',');

    $cachedIds = empty($cachedIds)
      ? []
      : explode(',', $cachedIds);
}

$order = new ProductOrder();
$order->fill($request->all());
$order->save();

Cache::put("cachedIds", array_merge($cachedIds, [$order->id]), 60 * 60);

return to_route('checkout', $product->url);

Solution

  • The fact you do $product->orders() implies you're keeping one cached entry per product. Is that right? In any case, you can use Cache::remember(key, ttl, callback) to achieve what you want.

    Let's say for this example $product's id is 1

    // If the cache has the key 'cached-order-ids-for-product-1' ?
    //     $id_array = Cache::get('cached-order-ids-for-product-1')
    // If the cache doesn't have the key 'cached-order-ids-for-product-1'
    //     Run callback
    //     $id_array = result of callback
    //     Create cache key 'cached-order-ids-for-product-1' and put result of callback as its value. Make it expire in the time specified in ttl
    $id_array = Cache::remember(
        key: 'cached-order-ids-for-product-'.$product->id,
        ttl: 60 * 60,
        callback: function () use ($product) {
            return $product->orders()
                ->whereNot('status', 'expired')
                ->implode('id', ',');
        }
    );
    

    And then every time you do something that would alter this value, simply use Cache::forget().

    $new_order = $product->orders()->create($request->validated());
    Cache::forget('cached-order-ids-for-product-'.$product->id);