Search code examples
phplaravelaggregatelaravel-collection

Sum total items in multiple shopping carts using Laravel collection methods


Say I have a shopping cart with relationship:

public function items()
{
  return $this->belongsToMany(Item::class, 'cart_item', 'cart_id', 'item_id')->withPivot('quantity');
}

Say I have multiple $carts with each $cart->items and I want to generate a list of all items in this cart with summation on pivot.quantity.

e.g:

[
  {'item': Apple, 'pivot.quantity': 2},
  {'item': Orange, 'pivot.quantity': 1},
]

[
  {'item': Apple, 'pivot.quantity': 4},
  {'item': Banana, 'pivot.quantity': 1},
]

Will produce

[
  {'item': Apple, 'pivot.quantity': 6},
  {'item': Banana, 'pivot.quantity': 1},
  {'item': Orange, 'pivot.quantity': 1},
]

My thought would be first to iterate through all $carts to produce a list like this:

[$cart[0]->items[0], $cart[0]->items[1], …, $cart[n]->items[n]]

Is it possible to achieve something like this in one line?

Then summation would be a trivial groupBy('item') followed with appropriate sum.


Solution

  • This should work

     $carts = [
       // this is your array;
     ];    
    
     $newCart = collect($carts)->flatten(1)->groupBy("item")->map(function($q){
        $item = $q->first()['item'];
    
        $quantity = $q->reduce(function($carry, $item){
            // Use this, as your quantity is not an object 
            // of pivot 
            return $carry + $item['pivot.quantity'];
            // use this if quantity is an object of pivot
            return $carry + $item['pivot']['quantity'];
        });
    
        return compact("item","quantity");
    })->values();
    

    Hope it helps.