contacts_events-8.x-1.x-dev/src/EventSubscriber/BookingConfirmedSubscriber.php
src/EventSubscriber/BookingConfirmedSubscriber.php
<?php namespace Drupal\contacts_events\EventSubscriber; use Drupal\commerce_order\Entity\OrderInterface; use Drupal\Component\Datetime\TimeInterface; use Drupal\contacts_events\OrderEventTransitionTrait; use Drupal\contacts_events\OrderItemStateTrait; use Drupal\contacts_events\OrderStateTrait; use Drupal\state_machine\Event\WorkflowTransitionEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Event subscriber for booking confirmation. */ class BookingConfirmedSubscriber implements EventSubscriberInterface { use OrderStateTrait; use OrderItemStateTrait; use OrderEventTransitionTrait; /** * The time. * * @var \Drupal\Component\Datetime\TimeInterface */ protected $time; /** * The event dispatcher. * * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface */ protected $eventDispatcher; /** * Constructs a new TimestampEventSubscriber object. * * @param \Drupal\Component\Datetime\TimeInterface $time * The time service. * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher * The event dispatcher service. */ public function __construct(TimeInterface $time, EventDispatcherInterface $event_dispatcher) { $this->time = $time; $this->eventDispatcher = $event_dispatcher; } /** * {@inheritdoc} */ public static function getSubscribedEvents() { // phpcs:disable Drupal.Arrays.Array.LongLineDeclaration // Confirming line items should be the very first step before transitioning. $events['commerce_order.place.pre_transition'][] = ['confirmLineItems', 500]; // Set the confirmed time of line items. $events['contacts_events_order_items.confirm.pre_transition'][] = ['setConfirmedTime', 0]; // Override the line items booking window to prevent recalculation changes. $events['contacts_events_order_items.paid_in_full.pre_transition'][] = ['setBookingWindowOverridden', 0]; // Make sure confirmed_paid_in_full triggers additional events. $events['commerce_order.confirmed_paid_in_full.pre_transition'][] = ['fireOrderConfirmedPaidInFullAdditionalEvents', -999]; $events['commerce_order.confirmed_paid_in_full.post_transition'][] = ['fireOrderConfirmedPaidInFullAdditionalEvents', 90]; $events['contacts_events_order_items.confirmed_paid_in_full.pre_transition'][] = ['fireOrderItemConfirmedPaidInFullAdditionalEvents', -999]; $events['contacts_events_order_items.confirmed_paid_in_full.post_transition'][] = ['fireOrderItemConfirmedPaidInFullAdditionalEvents', 90]; // phpcs:enable return $events; } /** * Check whether this subscriber applies to the event. * * @param \Drupal\commerce_order\Entity\OrderInterface $order * The order we are checking. * * @return bool * Whether this subscriber applies to the given order. */ protected function applies(OrderInterface $order) { return $order->bundle() == 'contacts_booking'; } /** * Fire the additional pre transition events for paid in full and combined. * * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event * The confirm transition event. * @param string $event_name * The event name. */ public function fireOrderConfirmedPaidInFullAdditionalEvents(WorkflowTransitionEvent $event, $event_name) { /** @var \Drupal\commerce_order\Entity\OrderInterface $entity */ $entity = $event->getEntity(); if (!$this->applies($entity)) { return; } // We have skipped the place and paid_in_full steps so trigger any events // that we may have missed. $event_parts = explode('.', $event_name); $phase = $event_parts[2]; $this->dispatchTransitionEvent('place', $phase, $event, $entity); $this->dispatchTransitionEvent('paid_in_full', $phase, $event, $entity); } /** * Fire the additional post transition events for confirmed and paid in full. * * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event * The confirmed_paid_in_full transition event. * @param string $event_name * The event name. */ public function fireOrderItemConfirmedPaidInFullAdditionalEvents(WorkflowTransitionEvent $event, $event_name) { /** @var \Drupal\commerce_order\Entity\OrderItemInterface $entity */ $entity = $event->getEntity(); /** @var \Drupal\commerce_order\Entity\OrderInterface $order */ $order = $entity->getOrder(); if (!$this->applies($order)) { return; } // We have skipped the confirm and paid_in_full steps so trigger any events // that we may have missed. $event_parts = explode('.', $event_name); $phase = $event_parts[2]; $this->dispatchTransitionEvent('confirm', $phase, $event, $entity); $this->dispatchTransitionEvent('paid_in_full', $phase, $event, $entity); } /** * Sets the order item's confirmed timestamp. * * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event * The transition event. */ public function setConfirmedTime(WorkflowTransitionEvent $event) { /** @var \Drupal\commerce_order\Entity\OrderItemInterface $item */ $item = $event->getEntity(); if ($this->applies($item->getOrder()) && $item->hasField('confirmed') && $item->get('confirmed')->isEmpty()) { $item->set('confirmed', $this->time->getRequestTime()); } } /** * Sets the order item's booking window on payment. * * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event * The transition event. */ public function setBookingWindowOverridden(WorkflowTransitionEvent $event) { /** @var \Drupal\commerce_order\Entity\OrderItemInterface $item */ $item = $event->getEntity(); if ($this->applies($item->getOrder()) && $item->hasField('mapped_price')) { $item->get('mapped_price')->first()->set('booking_window_overridden', 1); } } /** * Confirm any line items when a booking is confirmed. * * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event * The transition event. */ public function confirmLineItems(WorkflowTransitionEvent $event) { /** @var \Drupal\commerce_order\Entity\OrderInterface $order */ $order = $event->getEntity(); if (!$this->applies($order)) { return; } foreach ($order->getItems() as $item) { // Ignore any order items that are not stateful. if (!$item->hasField('state')) { continue; } /** @var \Drupal\state_machine\Plugin\Field\FieldType\StateItem $state */ $state = $item->get('state')->first(); // Start by confirming the item, without saving. $save = $this->applyTransitionIfAllowed($state, 'confirm'); // Next check whether it can be moved to paid in full. $save = $this->checkOrderItemStatus($item) || $save; // Save if we have made any change. if ($save) { $item->save(); } } } }