contacts_events-8.x-1.x-dev/modules/contacts_events_segments/contacts_events_segments.module
modules/contacts_events_segments/contacts_events_segments.module
<?php
/**
* @file
* Contains contacts_events_segments.module.
*/
use Drupal\Component\Render\FormattableMarkup;
use Drupal\contacts_events\Entity\EventInterface;
use Drupal\contacts_events\Entity\EventType;
use Drupal\contacts_events\Entity\Ticket;
use Drupal\contacts_events\Entity\TicketInterface;
use Drupal\contacts_events_segments\Entity\Segment;
use Drupal\contacts_events_segments\Entity\SegmentInterface;
use Drupal\contacts_events_segments\PreRenderCallbacks;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Implements hook_entity_extra_field_info().
*/
function contacts_events_segments_entity_extra_field_info() {
$extra = [];
foreach (EventType::loadMultiple() as $bundle) {
$extra['contacts_event'][$bundle->id()]['form']['segments'] = [
'label' => new TranslatableMarkup('Day tickets'),
'visible' => FALSE,
];
}
return $extra;
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for contacts_events_form.
*/
function contacts_events_segments_form_contacts_event_form_alter(&$form, FormStateInterface $form_state, $form_id) {
/** @var \Drupal\Core\Entity\ContentEntityFormInterface $form_object */
$form_object = $form_state->getFormObject();
$form_display = $form_object->getFormDisplay($form_state);
if ($form_display->getComponent('segments')) {
$event = $form_object->getEntity();
$form['segments'] = [
'#type' => 'container',
];
$form['segments']['segments'] = [
'#type' => 'radios',
'#title' => new TranslatableMarkup('Does this event have day tickets?'),
// phpcs:ignore Drupal.Arrays.Array.LongLineDeclaration
'#parents' => array_merge($form['#parents'] ?? [], ['settings', 'segments']),
'#options' => [
EventInterface::STATUS_OPEN => new TranslatableMarkup('Open for bookings'),
EventInterface::STATUS_CLOSED => new TranslatableMarkup('Closed for new tickets'),
EventInterface::STATUS_DISABLED => new TranslatableMarkup('Day tickets disabled'),
],
'#default_value' => $event->getSetting('segments', EventInterface::STATUS_DISABLED),
EventInterface::STATUS_OPEN => [
'#description' => new TranslatableMarkup('The public can add and confirm enabled day tickets.'),
],
EventInterface::STATUS_CLOSED => [
'#description' => new TranslatableMarkup('Only staff can add or confirm new day tickets.'),
],
EventInterface::STATUS_DISABLED => [
'#description' => new TranslatableMarkup('Day tickets and configuration are disabled for this event.'),
],
];
foreach ($form['segments']['segments']['#options'] as $value => $title) {
$form['segments']['segments'][$value]['#title'] = new FormattableMarkup('<strong>@title</strong>', [
'@title' => $title,
]);
}
}
}
/**
* Allowed values callback for the segment day field.
*
* @see \callback_allowed_values_function()
*/
function contacts_events_segments_segment_day_options(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL, &$cacheable = TRUE) {
if (!$entity) {
return [];
}
$cacheable = FALSE;
// We can't handle values for non-events.
if (!$entity instanceof SegmentInterface) {
return [];
}
$event = $entity->getEvent();
$options = [];
/** @var \Drupal\Core\Datetime\DrupalDateTime|null $date */
$date = clone $event->get('date')->start_date;
if (!$date) {
return [];
}
$date->setTime(0, 0, 0);
/** @var \Drupal\Core\Datetime\DrupalDateTime|null $end */
$end = $event->get('date')->end_date;
do {
$options[] = $date->format('D j F');
$date->add(new DateInterval('P1D'));
} while ($end && $end->getTimestamp() > $date->getTimestamp());
return $options;
}
/**
* Implements hook_field_widget_WIDGET_TYPE_form_alter().
*/
function contacts_events_segments_field_widget_options_buttons_form_alter(&$element, FormStateInterface $form_state, $context) {
/** @var \Drupal\Core\Field\FieldItemListInterface $items */
$items = $context['items'];
/** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
$field_definition = $items->getFieldDefinition();
if ($field_definition->getTargetEntityTypeId() !== 'contacts_ticket' || $field_definition->getName() !== 'segments') {
return;
}
$ticket = $items->getEntity();
if (!$ticket instanceof TicketInterface || !$ticket->get('event')->target_id) {
return;
}
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
$field_manager = \Drupal::service('entity_field.manager');
$fields = $field_manager->getFieldDefinitions('contacts_event_segment', 'contacts_event_segment');
if (isset($fields['day']) && isset($fields['part'])) {
/** @var \Drupal\contacts_events_segments\Entity\SegmentInterface $entity */
$entity = Segment::create(['event' => $ticket->get('event')->target_id]);
$element['#segment_parts'] = $fields['part']->getFieldStorageDefinition()->getOptionsProvider('value', $entity)->getPossibleOptions();
$element['#segment_days'] = $fields['day']->getFieldStorageDefinition()->getOptionsProvider('value', $entity)->getPossibleOptions();
$element['#pre_render'][] = [
PreRenderCallbacks::class,
'preRenderSegmentsTicketEventSegmentsCheckboxTable',
];
}
}
/**
* Implements hook_contacts_events_ticket_form_alter().
*/
function contacts_events_segments_contacts_events_ticket_form_alter(array &$form, FormStateInterface $form_state, Ticket $ticket, string $display_mode) {
if (!isset($form['segments'])) {
return;
}
/** @var \Drupal\contacts_events_segments\Access\SegmentsAccessChecker $access */
$access = Drupal::service('access_check._contacts_events_segments._contacts_events_segments');
// Do not render the day tickets UI if day tickets are disabled
// of if they're closed and the user is not staff.
if (!$access->bookingAccess($ticket->getEvent())) {
$form['segments']['#access'] = FALSE;
return;
}
// Add a header.
$form['segments_heading'] = [
'#type' => 'html_tag',
'#tag' => 'h3',
'#weight' => $form['segments']['#weight'] - 0.2,
'#value' => $form['segments']['widget']['#title'],
];
$form['segments']['widget']['#title_display'] = 'none';
// Add a checkbox.
$form['segments_enabled'] = [
'#type' => 'checkbox',
'#title' => new TranslatableMarkup('This person only wants day tickets'),
'#description' => new TranslatableMarkup('Day tickets do not grant overnight access to the site or accommodation.'),
'#default_value' => !empty($form['segments']['widget']['#default_value']),
'#weight' => $form['segments']['#weight'] - 0.1,
];
// Make the main widget dependent on the checkbox.
$parents = $form['#parents'] ?? [];
$parents[] = 'segments_enabled';
$name = array_shift($parents);
if ($parents) {
$name = $name . '[' . implode('][', $parents) . ']';
}
$form['segments']['#states']['visible'] = [
':input[name="' . $name . '"]' => ['checked' => TRUE],
];
// Register the segments fields to trigger a price update.
/** @var \Drupal\contacts_events\Element\AjaxUpdate $price_updater */
$price_updater = $form['price_update']['#element'];
$price_updater->registerElementToRespondTo($form['segments']['widget']);
}
/**
* Implements hook_views_data_alter().
*/
function contacts_events_segments_views_data_alter(array &$data) {
$data['contacts_ticket__segments']['segments_target_id']['filter']['id'] = 'contacts_event_segment';
}
