contacts_events-8.x-1.x-dev/src/Cron/BookingWindowCronBase.php
src/Cron/BookingWindowCronBase.php
<?php
namespace Drupal\contacts_events\Cron;
use Drupal\Component\Datetime\Time;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
/**
* A base class for performing actions based on booking window transistions.
*/
abstract class BookingWindowCronBase extends CronBase {
/**
* Event entity storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $eventStorage;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* An offset to apply when checking booking windows.
*
* A positive offset will mean the action is performed that interval before
* the deadline change.
*
* @var \DateInterval|null
*/
protected $dateOffset;
/**
* Construct the booking window transition cron base class.
*
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Component\Datetime\Time $time
* The time service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
*
* @throws \Exception
* Thrown if the STATE_LAST_RUN constant is not set.
*/
public function __construct(StateInterface $state, Time $time, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
parent::__construct($state, $time);
$this->eventStorage = $entity_type_manager->getStorage('contacts_event');
$this->entityFieldManager = $entity_field_manager;
}
/**
* {@inheritdoc}
*
* @todo Refactor this so multiple order item types get handle as one action.
*/
protected function doInvoke() {
// Get the booking window fields and the order item types they affect.
$window_fields = [];
$field_map = $this->entityFieldManager->getFieldMapByFieldType('price_map');
if (isset($field_map['contacts_event'])) {
foreach ($field_map['contacts_event'] as $field_name => $field_info) {
foreach ($field_info['bundles'] as $bundle) {
$definition = $this->entityFieldManager
->getFieldDefinitions('contacts_event', $bundle)[$field_name];
if ($window_field = $definition->getSetting('booking_window_field')) {
$window_definition = $this->entityFieldManager
->getFieldDefinitions('contacts_event', $bundle)[$window_field];
$order_item_type = $definition->getSetting('order_item_type');
$window_fields[$window_field][$order_item_type] = $window_definition->getSetting('datetime_type');
}
}
}
}
// If we have no fields, there's nothing to do.
if (empty($window_fields)) {
return;
}
// Look for any events which have passed a booking window.
$now = $this->getCurrentTime();
$last_run = $this->getLastRunTime();
// Apply an offset if there is one.
if ($this->dateOffset) {
$now->add($this->dateOffset);
if ($last_run) {
$last_run->add($this->dateOffset);
}
}
foreach ($window_fields as $field_name => $order_item_types) {
foreach ($order_item_types as $order_item_type => $date_type) {
$query = $this->eventStorage->getQuery();
$query->accessCheck(FALSE);
// Get the database date format.
if ($date_type == DateTimeItem::DATETIME_TYPE_DATE) {
$format = DateTimeItemInterface::DATE_STORAGE_FORMAT;
}
else {
$format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
}
// Put the two cut off checks in an OR condition group.
$or = $query->orConditionGroup();
$query->condition($or);
$cut_off_condition = $query->andConditionGroup();
$or->condition($cut_off_condition);
$cut_off_confirmed_condition = $query->andConditionGroup();
$or->condition($cut_off_confirmed_condition);
// Check the cut off is before now.
$cut_off_condition->condition("{$field_name}.cut_off", $now->format($format), '<');
$cut_off_confirmed_condition->condition("{$field_name}.cut_off_confirmed", $now->format($format), '<');
// If we have a last run, only look more recent than that.
if ($last_run) {
$cut_off_condition->condition("{$field_name}.cut_off", $last_run->format($format), '>=');
$cut_off_confirmed_condition->condition("{$field_name}.cut_off_confirmed", $last_run->format($format), '>=');
}
// Queue up any orders for recalculation.
$event_ids = $query->execute();
if (!empty($event_ids)) {
$this->runActionsForEvents($event_ids, [$order_item_type]);
}
}
}
}
/**
* Run the actions for given events/order item types.
*
* @param int[] $event_ids
* An array of event IDs to perform an action for.
* @param string[] $order_item_types
* The order item types the action is relevant for.
*/
abstract protected function runActionsForEvents(array $event_ids, array $order_item_types): void;
}
