contacts_events-8.x-1.x-dev/src/Plugin/Field/FieldType/BookingWindowsItemList.php
src/Plugin/Field/FieldType/BookingWindowsItemList.php
<?php
namespace Drupal\contacts_events\Plugin\Field\FieldType;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Form\FormStateInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
/**
* Represents the booking windows field.
*/
class BookingWindowsItemList extends FieldItemList {
/**
* {@inheritdoc}
*
* @var \Drupal\contacts_events\Plugin\Field\FieldType\BookingWindowsItem[]
*/
protected $list = [];
/**
* {@inheritdoc}
*/
public function getConstraints() {
$constraints = parent::getConstraints();
$constraints[] = $this->getTypedDataManager()
->getValidationConstraintManager()
->create('BookingWindowsUnique', []);
return $constraints;
}
/**
* {@inheritdoc}
*/
public function preSave() {
parent::preSave();
usort($this->list, [$this, 'sortItems']);
}
/**
* Sorting callback for booking windows.
*
* Will sort by cut off confirmed ascending, cut off ascending, with NULL cut
* offs last.
*
* @param \Drupal\contacts_events\Plugin\Field\FieldType\BookingWindowsItem $a
* The first booking window.
* @param \Drupal\contacts_events\Plugin\Field\FieldType\BookingWindowsItem $b
* The second booking window.
*
* @return int
* The sort comparison result.
*/
public static function sortItems(BookingWindowsItem $a, BookingWindowsItem $b) {
// Start by comparing the confirmed cut off (the earlier).
$a_cut_off_confirmed = $a->cut_off_confirmed ?? 'A';
$b_cut_off_confirmed = $b->cut_off_confirmed ?? 'A';
if ($a_cut_off_confirmed !== $b_cut_off_confirmed) {
return $a_cut_off_confirmed <=> $b_cut_off_confirmed;
}
// Then compare the paid in full cut off.
$a_cut_off = $a->cut_off ?? 'A';
$b_cut_off = $b->cut_off ?? 'A';
return $a_cut_off <=> $b_cut_off;
}
/**
* A machine name callback for checking the uniqueness of IDs.
*
* @param string $value
* The ID being checked.
* @param array $element
* The element array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return bool
* Whether the ID is unique.
*/
public static function checkUnique($value, array $element, FormStateInterface $form_state) {
$parents = $element['#parents'];
array_pop($parents);
$delta_checking = array_pop($parents);
$submitted_values = $form_state->getValue($parents);
foreach ($submitted_values as $delta => $values) {
if (in_array($delta, [$delta_checking, 'add_more'])) {
continue;
}
if ($values['id'] == $value) {
return TRUE;
}
}
return FALSE;
}
/**
* Find the appropriate window for a specific date.
*
* @param \Drupal\Core\Datetime\DrupalDateTime|null $confirmed_date
* The date the item was confirmed, or NULL if it's not.
* @param \Drupal\Core\Datetime\DrupalDateTime|null $comparison_date
* The date to check against, or NULL to use now.
*
* @return \Drupal\contacts_events\Plugin\Field\FieldType\BookingWindowsItem|null
* The booking window item, or NULL if none is found.
*/
public function findWindow(?DrupalDateTime $confirmed_date, DrupalDateTime $comparison_date = NULL): ?BookingWindowsItem {
if ($this->isEmpty()) {
return NULL;
}
if (!isset($comparison_date)) {
$comparison_date = new DrupalDateTime();
}
// If the ticket is not yet confirmed, treat it as though it is confirmed
// on the comparison date.
if (!isset($confirmed_date)) {
$confirmed_date = $comparison_date;
}
// If our precision is by day, set our time to 00:00:00.
if ($this->getSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) {
$comparison_date->setTime(0, 0, 0);
$confirmed_date->setTime(0, 0, 0);
}
// Ensure booking windows are sorted.
usort($this->list, [$this, 'sortItems']);
// Loop through until we find our match.
foreach ($this->list as $window) {
// If we have a paid in full date, ensure we are not past that.
if ($window->cut_off && $window->date < $comparison_date) {
continue;
}
// Ensure the item was confirmed in time.
if ($window->cut_off_confirmed && $window->date_confirmed < $confirmed_date) {
continue;
}
// Otherwise we have a match, so return the window.
return $window;
}
return NULL;
}
}
