2021-06-30 07:00:00 +00:00
|
|
|
|
---
|
2021-07-09 16:32:30 +00:00
|
|
|
|
title: Debugging Drupal Commerce Promotions and Adjustments using Illuminate Collections (Drupal 8)
|
2021-06-30 07:00:00 +00:00
|
|
|
|
date: 2018-10-24
|
2021-07-09 16:32:30 +00:00
|
|
|
|
excerpt: Using Laravel’s Illuminate Collections to debug an issue with a Drupal Commerce promotion.
|
2021-06-30 07:00:00 +00:00
|
|
|
|
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
|