contacts_events-8.x-1.x-dev/src/Plugin/Field/FieldWidget/EventDropdown.php
src/Plugin/Field/FieldWidget/EventDropdown.php
<?php
namespace Drupal\contacts_events\Plugin\Field\FieldWidget;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of 'contacts_events_dropdown'.
*
* @FieldWidget(
* id = "contacts_events_dropdown",
* label = @Translation("Event Dropdown"),
* field_types = {
* "entity_reference"
* }
* )
*/
class EventDropdown extends WidgetBase implements ContainerFactoryPluginInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* Constructs widget plugin.
*
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The definition of the field to which the widget is associated.
* @param array $settings
* The widget settings.
* @param array $third_party_settings
* Any third party settings.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager service.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, EntityTypeManagerInterface $entity_type_manager, TimeInterface $time) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
$this->entityTypeManager = $entity_type_manager;
$this->time = $time;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['third_party_settings'],
$container->get('entity_type.manager'),
$container->get('datetime.time')
);
}
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$multiple = $this->fieldDefinition->getFieldStorageDefinition()->isMultiple();
$values = $items->getValue();
if ($multiple) {
$default_value = array_column($values, 'target_id');
}
else {
$default_value = !empty($values) && !empty($values[0]['target_id']) ? $values[0]['target_id'] : NULL;
}
$user_id = $items->getEntity()->uid->target_id;
$options = [];
if ($upcoming = $this->upcomingEvents($user_id)) {
$options[$this->t('Upcoming events')->render()] = $upcoming;
}
if ($last_6_month = $this->previousEvents($user_id, strtotime('-6 months'))) {
$options[$this->t('Last 6 months')->render()] = $last_6_month;
}
if ($last_12_month = $this->previousEvents($user_id, strtotime('-12 months'), strtotime('-6 months'))) {
$options[$this->t('Last 12 months')->render()] = $last_12_month;
}
$element += [
'#type' => 'select',
'#title' => $this->t('Event'),
'#description' => $this->t('Assign this migration to an existing group.'),
'#options' => $options,
'#target_type' => $this->getFieldSetting('target_type'),
'#multiple' => $multiple,
'#default_value' => $default_value,
'#required' => $this->fieldDefinition->isRequired(),
];
return ['target_id' => $element];
}
/**
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
return $values[0]['target_id'];
}
/**
* {@inheritdoc}
*/
public static function isApplicable(FieldDefinitionInterface $field_definition) {
$handler = $field_definition->getSetting('handler');
return $handler == 'default:contacts_event';
}
/**
* Get a list of upcoming events for #options.
*
* @param int|null $user_id
* The ID of the user to present previous events for.
* Restricts the events to ones the user doesn't have an order for. Use NULL
* to get all previous events.
*
* @return array
* An array of event labels keyed by event id.
*/
protected function upcomingEvents($user_id = NULL) {
$request_time = new DrupalDateTime();
$request_time->setTimestamp($this->time->getRequestTime());
$query = $this->entityTypeManager->getStorage('contacts_event')->getQuery();
$query->accessCheck(TRUE);
$query->condition('date.end_value', $request_time->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT), '>=');
$query->sort('date.end_value', 'ASC');
$result = $query->execute();
$events = $this->entityTypeManager->getStorage('contacts_event')->loadMultiple($result);
$existing_event_orders = $user_id ? $this->existingOrderEvents($user_id, array_keys($events)) : [];
$options = [];
foreach ($events as $event) {
// If there is already an order for this event and user then do not add
// it to the options.
if (empty($existing_event_orders[$event->id()])) {
$options[$event->id()] = $event->label();
}
}
return $options;
}
/**
* Get a list of previous events for #options.
*
* @param int|null $user_id
* The ID of the user to present previous events for.
* Restricts the events to ones the user doesn't have an order for. Use NULL
* to get all previous events.
* @param int $start_timestamp
* Provide the start time that all events must be after.
* @param int|null $end_timestamp
* Optionally provide an end time that all events must be before.
*
* @return array
* An array of event labels keyed by event id.
*/
protected function previousEvents($user_id, $start_timestamp, $end_timestamp = NULL) {
$start_time = new DrupalDateTime();
$start_time->setTimestamp($start_timestamp);
if (!$end_timestamp) {
$end_timestamp = $this->time->getRequestTime();
}
$end_time = new DrupalDateTime();
$end_time->setTimestamp($end_timestamp);
$query = $this->entityTypeManager->getStorage('contacts_event')->getQuery();
$query->accessCheck(TRUE);
$query->condition('date.end_value', $start_time->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT), '>=');
$query->condition('date.end_value', $end_time->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT), '<=');
$query->sort('date.end_value', 'DESC');
$result = $query->execute();
$events = $this->entityTypeManager->getStorage('contacts_event')->loadMultiple($result);
$existing_event_orders = $user_id ? $this->existingOrderEvents($user_id, array_keys($events)) : [];
$options = [];
foreach ($events as $event) {
// If there is already an order for this event and user then do not add
// it to the options.
if (empty($existing_event_orders[$event->id()])) {
$options[$event->id()] = $event->label();
}
}
return $options;
}
/**
* Get all the events that a user has existing orders for.
*
* @param int $user_id
* The ID of the user to get events for.
* @param array|null $event_ids
* Specific event IDs to check if the user has orders for.
*
* @return array
* An array of order IDs keyed by event ID for the user.
*/
protected function existingOrderEvents($user_id, $event_ids = NULL) {
$order_query = $this->entityTypeManager->getStorage('commerce_order')->getQuery();
$order_query->accessCheck(TRUE);
$order_query->condition('uid', $user_id);
$order_query->condition('type', 'contacts_booking');
if ($event_ids) {
$order_query->condition('event', $event_ids, 'IN');
}
$order_result = $order_query->execute();
$order_events = [];
$orders = $this->entityTypeManager->getStorage('commerce_order')->loadMultiple($order_result);
foreach ($orders as $order) {
$order_events[$order->get('event')->target_id] = $order->id();
}
return $order_events;
}
}
