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();
}
}
}
}
