Skip to content

Instantly share code, notes, and snippets.

@mglaman
Created August 13, 2019 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mglaman/2925bf398a35cc9c7fc1008ee65a7280 to your computer and use it in GitHub Desktop.
Save mglaman/2925bf398a35cc9c7fc1008ee65a7280 to your computer and use it in GitHub Desktop.
Destructable performance wins
services:
commerce_stripe.order_events_subscriber:
class: Drupal\commerce_stripe\EventSubscriber\OrderEventsSubscriber
arguments: ['@entity_type.manager']
tags:
- { name: needs_destruction }
- { name: event_subscriber }
<?php
namespace Drupal\commerce_stripe\EventSubscriber;
use Drupal\commerce_order\Event\OrderEvent;
use Drupal\commerce_order\Event\OrderEvents;
use Drupal\commerce_price\Calculator;
use Drupal\commerce_price\Price;
use Drupal\commerce_stripe\Plugin\Commerce\PaymentGateway\StripeInterface;
use Drupal\Core\DestructableInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Stripe\Error\Base as StripeError;
use Stripe\PaymentIntent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Subscribers to order events for the Stripe integration.
*/
class OrderEventsSubscriber implements EventSubscriberInterface, DestructableInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The intent IDs that need updating.
*
* @var int[]
*/
protected $updateList = [];
/**
* Constructs a new OrderEventsSubscriber object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
OrderEvents::ORDER_UPDATE => 'onOrderUpdate',
];
}
/**
* {@inheritdoc}
*/
public function destruct() {
foreach ($this->updateList as $intent_id => $amount) {
try {
PaymentIntent::update($intent_id, ['amount' => $amount]);
}
catch (StripeError $e) {
// Allow sync errors to silently fail.
}
}
}
/**
* Ensures the Stripe payment intent is up to date.
*
* @param \Drupal\commerce_order\Event\OrderEvent $event
* The event.
*/
public function onOrderUpdate(OrderEvent $event) {
$order = $event->getOrder();
$gateway = $order->get('payment_gateway');
if ($gateway->isEmpty()) {
return;
}
$plugin = $gateway->entity->getPlugin();
if (!$plugin instanceof StripeInterface) {
return;
}
$intent_id = $order->getData('stripe_intent');
if ($intent_id !== NULL) {
$amount = $this->toMinorUnits($order->getTotalPrice());
$this->updateList[$intent_id] = $amount;
}
}
/**
* Converts the given amount to its minor units.
*
* For example, 9.99 USD becomes 999.
*
* @todo Remove after https://www.drupal.org/node/2944281 is fixed.
*
* @param \Drupal\commerce_price\Price $amount
* The amount.
*
* @return int
* The amount in minor units, as an integer.
*/
private function toMinorUnits(Price $amount) {
$currency_storage = $this->entityTypeManager->getStorage('commerce_currency');
/** @var \Drupal\commerce_price\Entity\CurrencyInterface $currency */
$currency = $currency_storage->load($amount->getCurrencyCode());
$fraction_digits = $currency->getFractionDigits();
$number = $amount->getNumber();
if ($fraction_digits > 0) {
$number = Calculator::multiply($number, pow(10, $fraction_digits));
}
return round($number, 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment