Search code examples
phplaraveleloquentlaravel-query-builder

How to avoid multiple foreach loop in laravel


I am using a query to fetch data from the database. after fetching I am adding one extra attribute to each object but for that i have to use three foreach loop I want to avoid that foreach loop. How I can do this

here is my code for query

$invoices = Invoice::when(!empty($request->customer_id), function ($q) use ($request) {
      return $q->where('customer_id', $request->customer_id);
    })->where('start_date', '>=', $request->start_date)->whereDate('end_date', '<=', $request->end_date)->when(!empty($request->rate_zone_id), function ($q) use ($request) {
      $q->whereHas('consignments_invoices.charges', function ($query) use ($request) {
        $query->where('rate_zone_id', $request->rate_zone_id);
      });
    })->withCount(['consignments_invoices'])->with(['customers:id,name', 'invoice_totals', 'consignments_invoices.charges'])->get();

Here I am adding one more attribute in object with help of foreach loop

foreach ($invoices as $invoice) {
        $invoice->setAttribute('rate_zone_income','');
        if (!empty($request->rate_zone_id)) {
        $rate_zone_income = 0;
        foreach ($invoice->consignments_invoices as $consignment) {

          foreach ($consignment->charges as $charge) {
            if ($charge->rate_zone_id == $request->rate_zone_id) {
              $rate_zone_income += $charge->income;
            }
          }
        }
        $invoice->setAttribute('rate_zone_income',$rate_zone_income);
      }
    }

Solution

  • Why not using accessors:

    class Invoice extends Model
    {
        // ...
        public function getRateZoneIncomeAttribute($rateZoneId = null)
        {
            if (empty($rateZoneId)) {
                return '';
            }
    
            return $invoice->consignments_invoices->reduce(function($rate_zone_income, $consignment) {
                return $cosignment->charges->reduce(function($rate_zone_income, $charge) {
                    if ($charge->rate_zone_id == $rateZoneId) {
                        $rate_zone_income += $charge->income;
                    }
                    return $rate_zone_income;
                }, $rate_zone_income);
            }, 0);
        }
        // ...
    }