3.9 KiB
title | date | excerpt | tags | promoted | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Debugging Drupal Commerce Promotions and Adjustments using Illuminate Collections (Drupal 8) | 2018-10-24 | Using Laravel’s Illuminate Collections to debug an issue with a Drupal Commerce promotion. |
|
true |
Today I found another instance where I decided to use Illuminate Collections within my Drupal 8 code; whilst I was debugging an issue where a Drupal Commerce 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:
$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 to output the order items.
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.
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 theflatten()
andmap()
methods. - Use higher order messages to delegate straight to the
getAdjustments()
method on the order, rather than having to create a closure and call the method within it.
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.
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()
.
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!