Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Garet's avatar
Level 3

Caching query data for a single request

I have a model called Product and a model called Price.

Each product has its own price, which is not related to the Price model. The Price model is an independent set of data managed elsewhere.

In my Price table I have a list of original prices alongside a replacement price, for example:

Original Price   New Price
100              250
500              599
1000             1200

When I fetch a Product, let's call it "Widget", if its price is one of $100, $500 or $1000 then I want to show the corresponding New Price from the Price table. If the product's price is something else, for example $50, then I want to just show the original value.

In my Product model I have:

public function getPriceAttribute($price)
{
    $prices = Price::pluck('new_price', 'original_price')->toArray();
    return $prices[ $price ] ?? $price;
}

This work okay, but I am wanting to cache the price data so that I don't have to query the Price table every single time I display a product price.

Caching in Laravel is generally for a set amount of time. I wondered if it was possible to cache this data just for a single request. Or whether I can aquire the data from outside of the model a single time and somehow inject it, so that my Product model isn't intrinsically reliant on the Price model.

Thanks

0 likes
4 replies
tykus's avatar

This should work using a single query - the coalesce operation will do the fallback wherever there is no match:

$products = Product::selectRaw('products.*, coalesce(prices.new_price, products.price) as price')
    ->leftJoin('prices', 'products.price', 'prices.original_price')
	->get();

This would mean caching is no longer required.

Garet's avatar
Level 3

The problem with that method, is I would have to do that join anywhere where I query the products.

The beauty with the getPriceAttribute method is I don't have to remember to specifically join or lookup the price data from lots of different places.

tykus's avatar

If you really want to cache only for the current request; then the trick is to use the array cache driver. This should be the correct syntax:

public function getPriceAttribute($price)
{
    $prices = cache()->driver('array')
        ->remember('prices', fn () => Price::pluck('new_price', 'original_price')->toArray());
    return $prices[ $price ] ?? $price;
}

I personally would prefer the query joins approach using a global scope

Please or to participate in this conversation.