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

Sinres's avatar

How to make foreach with query better?

Hello!

In my code I get a products list with products quantity to send for orders and some complaints. This code is not good because I use query in foreach. How I can do this better?

class GetProductsDestinationsList
{
    public function __invoke()
    {
        $orderProducts = OrderProduct::where('status', OrderProductStatusNew::$name)
            ->select('product_id', 'size')
            ->groupBy('product_id', 'size')
            ->get()
            ->toArray();

        $productsDestinationsList = [];
        foreach ($orderProducts as $orderProduct) {
            $kioskOrders = $this->getOrders(Kiosk::class, $orderProduct);
            $webShopOrders = $this->getOrders(Shop::class, $orderProduct);
            $complaints = $this->getComplaints($orderProduct);

            $kioskOrdersNumbers = [];
            foreach ($kioskOrders as $kioskOrder) {
                $kioskOrdersNumbers[] = $kioskOrder['number'];
            }

            $webShopOrdersNumbers = [];
            foreach ($webShopOrders as $webShopOrder) {
                $webShopOrdersNumbers[] = $webShopOrder['number'];
            }

            $complaintsNumbers = [];
            foreach ($complaints as $complaint) {
                $complaintsNumbers[] = $complaint['number'];
            }

            $productsDestinationsList[] = [
                'product_id' => $orderProduct['product_id'],
                'size' => $orderProduct['size'],
                'webshop_orders' => [
                    'count' => count($webShopOrders),
                    'numbers' => $webShopOrdersNumbers
                ],
                'kiosk_orders' => [
                    'count' => count($kioskOrders),
                    'numbers' => $kioskOrdersNumbers
                ],
                'complaints' => [
                    'count' => count($complaints),
                    'numbers' => $complaintsNumbers
                ]
            ];
        }

        return response()->json(['data' => $productsDestinationsList], 200);
    }

    private function getOrders($domain, $product): array
    {
        return Order::with('orderProducts')
            ->where('orderable_type', '=', $domain)
            ->where('status', OrderNew::$name)
            ->whereHas('orderProducts', function ($query) use ($product) {
                return $query->where('product_id', '=', $product['product_id'])
                    ->where('size', '=', $product['size'])
                    ->where('status', '=', OrderProductStatusNew::$name)
            })
            ->get()
            ->toArray();
    }

    private function getComplaints($product): array
    {
        return Complaint::with('document')
            ->whereHas('document', function ($query) use ($product) {
                $query->where('product_id', '=', $product['product_id'])
                    ->where('product_size', '=', $product['size']);
            })
            ->get()
            ->toArray();
    }
}
0 likes
1 reply
gty's avatar

Eager Load the Orders Kiosk and Shop in the OrderProduct query, same with the Complaints:

$orderProducts = OrderProduct::where('status', OrderProductStatusNew::$name)
            ->select('product_id', 'size')
			->with('orders', fn ($orders) =>
						$orders->whereIn('orderable_type', [Kiosk::class, Shop::class])
           				->where('status', OrderNew::$name)
			)
			->with('complaints')
            ->groupBy('product_id', 'size')
            ->get()
			->each(function ($orderProduct) {
						...
			});
1 like

Please or to participate in this conversation.