--- title: Debugging Drupal Commerce Promotions and Adjustments using Illuminate Collections (Drupal 8) date: 2018-10-24 excerpt: Using Laravel’s Illuminate Collections to debug an issue with a Drupal Commerce promotion. tags: - drupal - drupal-8 - drupal-commerce - drupal-planet - illuminate-collections - laravel-collections - php promoted: true --- Today I found another instance where I decided to use [Illuminate Collections][0] within my Drupal 8 code; whilst I was debugging an issue where a [Drupal Commerce][1] promotion was incorrectly being applied to an order. No adjustments were showing in the Drupal UI for that order, so after some initial investigation and finding that `$order->getAdjustments()` was empty, I determined that I would need to get the adjustments from each order item within the order. If the order were an array, this is how it would be structured in this situation: ```php $order = [ 'id' => 1, 'items' => [ [ 'id' => 1, 'adjustments' => [ ['name' => 'Adjustment 1'], ['name' => 'Adjustment 2'], ['name' => 'Adjustment 3'], ] ], [ 'id' => 2, 'adjustments' => [ ['name' => 'Adjustment 4'], ] ], [ 'id' => 3, 'adjustments' => [ ['name' => 'Adjustment 5'], ['name' => 'Adjustment 6'], ] ], ], ]; ``` ## Getting the order items I started by using `$order->getItems()` to load the order’s items, converted them into a Collection, and used the Collection’s `pipe()` method and the `dump()` function provided by the [Devel module][2] to output the order items. ```php collect($order->getItems()) ->pipe(function (Collection $collection) { dump($collection); }); ``` ## Get the order item adjustments Now we have a Collection of order items, for each item we need to get it’s adjustments. We can do this with `map()`, then call `getAdjustments()` on the order item. This would return a Collection of arrays, with each array containing it’s own adjustments, so we can use `flatten()` to collapse all the adjustments into one single-dimensional array. ```php collect($order->getItems()) ->map(function (OrderItem $order_item) { return $order_item->getAdjustments(); }) ->flatten(1); ``` There are a couple of refactors that we can do here though: - Use `flatMap()` to combine the `flatten()` and `map()` methods. - Use [higher order messages][3] to delegate straight to the `getAdjustments()` method on the order, rather than having to create a closure and call the method within it. ```php collect($order->getItems()) ->flatMap->getAdjustments(); ``` ## Filtering In this scenario, each order item had three adjustments - the correct promotion, the incorrect one and the standard VAT addition. I wasn’t concerned about the VAT adjustment for debugging, so I used `filter()` to remove it based on the result of the adjustment’s `getSourceId()` method. ```php collect($order->getItems()) ->flatMap->getAdjustments() ->filter(function (Adjustment $adjustment) { return $adjustment->getSourceId() != 'vat'; }); ``` ## Conclusion Now I have just the relevant adjustments, I want to be able to load each one to load it and check it’s conditions. To do this, I need just the source IDs. Again, I can use a higher order message to directly call `getSourceId()` on the adjustment and return it’s value to `map()`. ```php collect($order->getItems()) ->flatMap->getAdjustments() ->filter(function (Adjustment $adjustment) { return $adjustment->getSourceId() != 'vat'; }) ->map->getSourceId(); ``` This returns a Collection containing just the relevant promotion IDs being applied to the order that I can use for debugging. Now just to find out why the incorrect promotion was applying! [0]: https://laravel.com/docs/collections [1]: https://drupalcommerce.org [2]: https://www.drupal.org/project/devel [3]: https://laravel-news.com/higher-order-messaging