recurring_events-2.0.x-dev/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php
modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php
<?php
declare(strict_types=1);
namespace Drupal\recurring_events_registration\Plugin\Field\FieldWidget;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\Attribute\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\datetime_range\Plugin\Field\FieldWidget\DateRangeDefaultWidget;
use Drupal\user\Entity\Role;
/**
* Plugin implementation of the 'event registration' widget.
*/
#[FieldWidget(
id: "event_registration",
label: new TranslatableMarkup("Event registration widget"),
field_types: [
"event_registration",
],
)]
class EventRegistrationWidget extends DateRangeDefaultWidget {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'show_enable_waitlist' => TRUE,
] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$element['show_enable_waitlist'] = [
'#type' => 'radios',
'#options' => [
'1' => $this->t('Show'),
'0' => $this->t('Hide'),
],
'#title' => $this->t('Enable Waiting List'),
'#default_value' => $this->getSetting('show_enable_waitlist'),
'#description' => $this->t('This will show/hide the "Enable Waiting List" checkbox in the Add/Edit Series form'),
];
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = [];
$enable_waitlist = $this->getSetting('show_enable_waitlist') ? $this->t('On') : $this->t('Off');
$summary[] = $this->t('Enable Waiting list is: @value', ['@value' => $enable_waitlist]);
return $summary;
}
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element = parent::formElement($items, $delta, $element, $form, $form_state);
$element['#type'] = 'container';
$element['registration'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable Registration'),
'#description' => $this->t('Select this box to enable registrations for this event. By doing so you will be able to specify the capacity of the event, and if applicable enable a waitlist.'),
'#weight' => 0,
'#default_value' => $items[$delta]->registration ?: '',
];
$element['unique_email_address'] = [
'#type' => 'checkbox',
'#title' => $this->t('Restrict registration to once per email address?'),
'#description' => $this->t('Select this box to only allow an email address to register for an event one time.'),
'#weight' => 1,
'#default_value' => $items[$delta]->unique_email_address ?: '',
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
],
],
];
$role_options = [];
$roles = Role::loadMultiple();
if (!empty($roles)) {
foreach ($roles as $role) {
$role_options[$role->id()] = $role->label();
}
}
$element['permitted_roles'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Which roles can register for this series?'),
'#description' => $this->t('Select all the roles that can register, or leave blank to allow anybody to register.'),
'#weight' => 1,
'#default_value' => $items[$delta]->permitted_roles ? explode(',', $items[$delta]->permitted_roles) : [],
'#options' => $role_options,
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
],
],
];
$element['registration_type'] = [
'#type' => 'radios',
'#title' => $this->t('Registration Type'),
'#description' => $this->t('Select whether registrations are for the entire series, or for individual instances.'),
'#weight' => 2,
'#default_value' => $items[$delta]->registration_type ?: 'instance',
'#options' => [
'instance' => $this->t('Individual Event Registration'),
'series' => $this->t('Entire Series Registration'),
],
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
],
],
];
$element['registration_dates'] = [
'#type' => 'radios',
'#title' => $this->t('Registration Dates'),
'#description' => $this->t('Choose between open or scheduled registration. Open registration ends when the event begins.'),
'#weight' => 3,
'#default_value' => $items[$delta]->registration_dates ?: 'open',
'#options' => [
'open' => $this->t('Open Registration'),
'scheduled' => $this->t('Scheduled Registration'),
],
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
],
],
];
$element['series_registration'] = [
'#type' => 'fieldset',
'#title' => $this->t('Series Registration'),
'#weight' => 4,
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
':input[name="event_registration[0][registration_type]"]' => ['value' => 'series'],
':input[name="event_registration[0][registration_dates]"]' => ['value' => 'scheduled'],
],
],
'#element_validate' => [
[static::class, 'validateSeriesRegistration'],
],
];
$element['series_registration']['value'] = $element['value'];
$element['series_registration']['end_value'] = $element['end_value'];
unset($element['value']);
unset($element['end_value']);
$element['series_registration']['value']['#title'] = $this->t('Registration Opens');
$element['series_registration']['end_value']['#title'] = $this->t('Registration Closes');
$element['instance_registration'] = [
'#type' => 'fieldset',
'#title' => $this->t('Instance Registration'),
'#weight' => 4,
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
':input[name="event_registration[0][registration_type]"]' => ['value' => 'instance'],
':input[name="event_registration[0][registration_dates]"]' => ['value' => 'scheduled'],
],
],
];
$element['instance_registration']['instance_schedule_open'] = [
'#type' => 'select',
'#title' => $this->t('Registration Opens'),
'#description' => $this->t('Select when to open registration'),
'#weight' => 0,
'#default_value' => $items[$delta]->instance_schedule_open,
'#options' => [
'now' => $this->t('Now'),
'start' => $this->t('At the start of the event'),
'custom' => $this->t('Custom schedule'),
],
];
$element['instance_registration']['open_registration'] = [
'#type' => 'container',
'#weight' => 1,
'#states' => [
'visible' => [
':input[name="event_registration[0][instance_registration][instance_schedule_open]"]' => ['value' => 'custom'],
],
],
'#attributes' => [
'class' => 'container-inline',
],
];
$element['instance_registration']['open_registration']['instance_schedule_open_amount'] = [
'#type' => 'number',
'#title' => '',
'#weight' => 1,
'#default_value' => $items[$delta]->instance_schedule_open_amount ?? '1',
'#min' => 0,
];
$element['instance_registration']['open_registration']['instance_schedule_open_units'] = [
'#type' => 'select',
'#title' => '',
'#weight' => 2,
'#default_value' => $items[$delta]->instance_schedule_open_units ?? 'month',
'#options' => [
'month' => $this->t('months'),
'week' => $this->t('weeks'),
'day' => $this->t('days'),
'hour' => $this->t('hours'),
'minute' => $this->t('minutes'),
'second' => $this->t('seconds'),
],
'#suffix' => $this->t('before the event starts'),
];
$element['instance_registration']['instance_schedule_close'] = [
'#type' => 'select',
'#title' => $this->t('Registration Closes'),
'#description' => $this->t('Select when to close registration'),
'#weight' => 3,
'#default_value' => $items[$delta]->instance_schedule_close,
'#options' => [
'start' => $this->t('At the start of the event'),
'end' => $this->t('At the end of the event'),
'custom' => $this->t('Custom schedule'),
],
];
$element['instance_registration']['close_registration'] = [
'#type' => 'container',
'#weight' => 4,
'#states' => [
'visible' => [
':input[name="event_registration[0][instance_registration][instance_schedule_close]"]' => ['value' => 'custom'],
],
],
'#attributes' => [
'class' => 'container-inline',
],
];
$element['instance_registration']['close_registration']['instance_schedule_close_amount'] = [
'#type' => 'number',
'#title' => '',
'#weight' => 1,
'#default_value' => $items[$delta]->instance_schedule_close_amount ?? '1',
'#min' => 0,
];
$element['instance_registration']['close_registration']['instance_schedule_close_units'] = [
'#type' => 'select',
'#title' => '',
'#weight' => 2,
'#default_value' => $items[$delta]->instance_schedule_close_units ?? 'week',
'#min' => 0,
'#options' => [
'month' => $this->t('months'),
'week' => $this->t('weeks'),
'day' => $this->t('days'),
'hour' => $this->t('hours'),
'minute' => $this->t('minutes'),
'second' => $this->t('seconds'),
],
];
$element['instance_registration']['close_registration']['instance_schedule_close_type'] = [
'#type' => 'select',
'#title' => '',
'#weight' => 3,
'#default_value' => $items[$delta]->instance_schedule_close_type ?: '',
'#options' => [
'before' => $this->t('before the event starts'),
'after' => $this->t('after the event starts'),
],
];
$element['capacity'] = [
'#type' => 'number',
'#title' => $this->t('Total Number of Spaces Available'),
'#description' => $this->t('Maximum number of attendees available for each series, or individual event. Leave blank for unlimited.'),
'#weight' => 6,
'#default_value' => $items[$delta]->capacity ?: '',
'#min' => 0,
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
],
],
];
$enable_waitlist = $this->getSetting('show_enable_waitlist');
$waitlist_default_value = $enable_waitlist ? ($items[$delta]->waitlist ?? FALSE) : FALSE;
$items[$delta]->waitlist = 1;
$element['waitlist'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable Waiting List'),
'#description' => $this->t('Enable a waiting list if the number of registrations reaches capacity.'),
'#weight' => 7,
'#default_value' => $waitlist_default_value,
'#states' => [
'visible' => [
':input[name="event_registration[0][registration]"]' => ['checked' => TRUE],
],
],
'#access' => $enable_waitlist ? TRUE : FALSE,
];
return $element;
}
/**
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
foreach ($values as &$item) {
$item['value'] = $item['series_registration']['value'];
$item['end_value'] = $item['series_registration']['end_value'];
$item['instance_schedule_open'] = $item['instance_registration']['instance_schedule_open'];
$item['instance_schedule_open_amount'] = (int) $item['instance_registration']['open_registration']['instance_schedule_open_amount'];
$item['instance_schedule_open_units'] = $item['instance_registration']['open_registration']['instance_schedule_open_units'];
$item['instance_schedule_close'] = $item['instance_registration']['instance_schedule_close'];
$item['instance_schedule_close_amount'] = (int) $item['instance_registration']['close_registration']['instance_schedule_close_amount'];
$item['instance_schedule_close_units'] = $item['instance_registration']['close_registration']['instance_schedule_close_units'];
$item['instance_schedule_close_type'] = $item['instance_registration']['close_registration']['instance_schedule_close_type'];
$item['capacity'] = (int) $item['capacity'];
$selected_roles = array_filter($item['permitted_roles'], function ($i) {
return $i !== 0;
});
$item['permitted_roles'] = implode(',', $selected_roles);
unset($item['series_registration']);
unset($item['instance_registration']);
if (empty($item['value'])) {
$item['value'] = '';
}
if (empty($item['end_value'])) {
$item['end_value'] = '';
}
if (empty($item['registration'])) {
$item['registration'] = 0;
}
if (empty($item['registration_type'])) {
$item['registration_type'] = '';
}
if (empty($item['registration_dates'])) {
$item['registration_dates'] = '';
}
if (empty($item['capacity'])) {
$item['capacity'] = 0;
}
if (empty($item['waitlist'])) {
$item['waitlist'] = 0;
}
if (empty($item['instance_schedule_open'])) {
$item['instance_schedule_open'] = '';
}
if (empty($item['instance_schedule_open_amount'])) {
$item['instance_schedule_open_amount'] = 0;
}
if (empty($item['instance_schedule_open_units'])) {
$item['instance_schedule_open_units'] = '';
}
if (empty($item['instance_schedule_close'])) {
$item['instance_schedule_close'] = '';
}
if (empty($item['instance_schedule_close_amount'])) {
$item['instance_schedule_close_amount'] = 0;
}
if (empty($item['instance_schedule_close_units'])) {
$item['instance_schedule_close_units'] = '';
}
if (empty($item['instance_schedule_close_type'])) {
$item['instance_schedule_close_type'] = '';
}
if (empty($item['unique_email_address'])) {
$item['unique_email_address'] = 0;
}
if (empty($item['permitted_roles'])) {
$item['permitted_roles'] = '';
}
}
$values = parent::massageFormValues($values, $form, $form_state);
return $values;
}
/**
* Custom validation.
*/
public static function validateSeriesRegistration($element, FormStateInterface $form_state, array $form) {
// Check if Series Registration and Scheduled Registration dates are set.
$registration = $form_state->getValue('event_registration');
if (
$registration[0]['registration'] == TRUE
&& $registration[0]['registration_type'] == 'series'
&& $registration[0]['registration_dates'] == 'scheduled'
) {
if (empty($registration[0]['series_registration']['value']) || empty($registration[0]['series_registration']['end_value'])) {
$error = t('If Scheduled Registration is chosen, registration dates must be set.');
if (empty($registration[0]['series_registration']['value'])) {
$form_state->setError($element['value'], $error);
}
if (empty($registration[0]['series_registration']['end_value'])) {
$form_state->setError($element['end_value'], $error);
}
}
}
}
/**
* Validate callback to ensure that the start date <= the end date.
*
* @param array $element
* An associative array containing the properties and children of the
* generic form element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param array $complete_form
* The complete form structure.
*/
public function validateStartEnd(array &$element, FormStateInterface $form_state, array &$complete_form) {
$start_date = $element['series_registration']['value']['#value']['object'];
$end_date = $element['series_registration']['end_value']['#value']['object'];
if ($start_date instanceof DrupalDateTime && $end_date instanceof DrupalDateTime) {
if ($start_date->getTimestamp() !== $end_date->getTimestamp()) {
$interval = $start_date->diff($end_date);
if ($interval->invert === 1) {
$form_state->setError($element, $this->t('The @title end date cannot be before the start date', ['@title' => $element['#title']]));
}
}
}
}
}
