This repository has been archived on 2025-01-19. You can view files and clone it, but cannot push or open issues or pull requests.
oliverdavies.uk-old-sculpin/source/_posts/debugging-drupal-commerce-promotions-illiminate-collections.md
Oliver Davies 85a10c545b Run prettier on all *.md files
```
prettier '{app,source}/**/**.md' --write
```
2020-03-08 17:57:45 +00:00

3.9 KiB
Raw Permalink Blame History

title date excerpt tags promoted
Debugging Drupal Commerce Promotions and Adjustments using Illuminate Collections (Drupal 8) 2018-10-24 Using Laravels Illuminate Collections to debug an issue with a Drupal Commerce promotion.
drupal
drupal-8
drupal-commerce
drupal-planet
illuminate-collections
laravel-collections
php
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 orders items, converted them into a Collection, and used the Collections 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 its 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 its 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 the flatten() and map() 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 wasnt concerned about the VAT adjustment for debugging, so I used filter() to remove it based on the result of the adjustments 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 its 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 its 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!