4

I have a collection of objects grabbed out of my DB using Laravel's Eloquent ORM ( I am not using Laravel just integrated Eloquent into my own Framework ). I used the transform method to iterate over the collection and unserialize one of the columns of each record, then collapsed the collection to place all the unserialized objects in one array.

Here is the logic:

  $orders = Order::where('user', $user)->orderBy('id', 'desc')->get();

  $orders->transform(function($order, $key) {

    $order->cart = unserialize($order->cart);

    $items = $order->cart->items;

    return $items;
  });

  $collapsed = $orders->collapse();

And Output:

[
   {
      "qty": "2",
      "price": 200,
      "item": {
         "id": 1,
         "title": "Black Hoodie",
         "img": "https://s3.amazonaws.com/bucket/black-hoodie.jpg",
         "description": "Plain Black Hoodie.",
         "price": 100
      }
   },
   {
      "qty": "2",
      "price": 200,
      "item": {
         "id": 2,
         "title": "Green Hoodie",
         "img": "https://s3.amazonaws.com/bucket/green-hoodie.jpg",
         "description": "Plain Green Hoodie.",
         "price": 100
      }
   },
   {
      "qty": 1,
      "price": 100,
      "item": {
         "id": 2,
         "title": "Green Hoodie",
         "img": "https://s3.amazonaws.com/bucket/green-hoodie.jpg",
         "description": "Plain Green Hoodie.",
         "price": 100
      }
   },
   {
      "qty": 1,
      "price": 100,
      "item": {
         "id": 1,
         "title": "Black Hoodie",
         "img": "https://s3.amazonaws.com/bucket/black-hoodie.jpg",
         "description": "Plain Black Hoodie.",
         "price": 100
      }
   }
]

Now what I want to accomplish next is to combine all the identical objects in this array, ideally by their "item":{"id"} value, into one object - adding their qty and price properties together, leaving the item property the same.

My Desired Output Would Be

[
   {
      "qty": "3",
      "price": 300,
      "item": {
         "id": 1,
         "title": "Black Hoodie",
         "img": "https://s3.amazonaws.com/bucket/black-hoodie.jpg",
         "description": "Plain Black Hoodie.",
         "price": 100
      }
   },
   {
      "qty": "3",
      "price": 300,
      "item": {
         "id": 2,
         "title": "Green Hoodie",
         "img": "https://s3.amazonaws.com/bucket/green-hoodie.jpg",
         "description": "Plain Green Hoodie.",
         "price": 100
      }
   }
]

Eloquent has TONS of great methods available to work with collections, I'm just stuck on the right combination to efficiently achieve what I want to do.

1 Answer 1

1

Try this:

use Illuminate\Support\Fluent;
use Illuminate\Support\Collection;

// Mocking data to meet your requirements.
// Wrapping attributes inside fluent object,
// so we'll have almost same object like Eloquent model
$orders = new Collection([
    new Fluent([
        'qty' => 2,
        'price' => 200,
        'item' => new Fluent([
            'id' => 1,
            'price' => 100,
            'title' => 'Black Hoodie',
            'img' => 'https://s3.amazonaws.com/bucket/black-hoodie.jpg',
            'description' => 'Plain Black Hoodie.',
        ])
    ]),
    new Fluent([
        'qty' => 2,
        'price' => 200,
        'item' => new Fluent([
            'id' => 2,
            'price' => 100,
            'title' => 'Green Hoodie',
            'img' => 'https://s3.amazonaws.com/bucket/green-hoodie.jpg',
            'description' => 'Plain Green Hoodie.',
        ])
    ]),
    new Fluent([
        'qty' => 1,
        'price' => 100,
        'item' => new Fluent([
            'id' => 2,
            'price' => 100,
            'title' => 'Green Hoodie',
            'img' => 'https://s3.amazonaws.com/bucket/green-hoodie.jpg',
            'description' => 'Plain Green Hoodie.',
        ])
    ]),
    new Fluent([
        'qty' => 1,
        'price' => 100,
        'item' => new Fluent([
            'id' => 1,
            'price' => 100,
            'title' => 'Black Hoodie',
            'img' => 'https://s3.amazonaws.com/bucket/black-hoodie.jpg',
            'description' => 'Plain Black Hoodie.',
        ])
    ])
]);

// Here's something you might interested
$result = $orders->groupBy('item.id')
    ->map(function ($orders, $itemId) {
        return new Fluent([
            'qty' => $orders->sum('qty'), // calculating quantity
            'price' => $orders->sum('price'), // calculating total price
            'item' => $orders->first()->item // leave the item as it is
        ]);
    });

// You may evaluate the result here
dd($result);

Update

More "raw" example:

use Illuminate\Support\Collection;

$orderOne = [
    'id' => 1,
    'price' => 100,
    'title' => 'Black Hoodie',
    'img' => 'https://s3.amazonaws.com/bucket/black-hoodie.jpg',
    'description' => 'Plain Black Hoodie.',
];

$orderTwo = [
    'id' => 2,
    'price' => 100,
    'title' => 'Green Hoodie',
    'img' => 'https://s3.amazonaws.com/bucket/green-hoodie.jpg',
    'description' => 'Plain Green Hoodie.',
];

$orders = new Collection([
    [
        'qty' => 2,
        'price' => 200,
        'item' => $orderOne
    ],
    [
        'qty' => 2,
        'price' => 200,
        'item' => $orderTwo
    ],
    [
        'qty' => 1,
        'price' => 100,
        'item' => $orderTwo
    ],
    [
        'qty' => 1,
        'price' => 100,
        'item' => $orderOne
    ]
]);

$result = $orders->groupBy('item.id')
    ->map(function ($orders, $itemId) {
        return [
            'qty' => $orders->sum('qty'),
            'price' => $orders->sum('price'),
            'item' => $orders->first()['item']
        ];
    });

dd($result);
Sign up to request clarification or add additional context in comments.

1 Comment

... and just like that your simplistic yet ingenious solution makes me feel brainless. At least I can say i was in the right direction haha! Gracias!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.