From 678ee3b5dbc4f56a369ad0228034edc8e6aa0e6f Mon Sep 17 00:00:00 2001 From: owenbush <owenbush@2765259.no-reply.drupal.org> Date: Mon, 30 Mar 2020 10:39:32 -0600 Subject: [PATCH] Issue #3090658 by owenbush, naresh_bavaskar, siddhant.bhosale, the_glitch: Add Event Series crashes on save when end date or start date isn't selected --- src/Form/EventSeriesForm.php | 7 +- .../ConsecutiveRecurringDateWidget.php | 81 +++++++++++++-- .../FieldWidget/DailyRecurringDateWidget.php | 51 +++++++++- .../MonthlyRecurringDateWidget.php | 99 ++++++++++++++++--- .../FieldWidget/WeeklyRecurringDateWidget.php | 55 ++++++++++- 5 files changed, 262 insertions(+), 31 deletions(-) diff --git a/src/Form/EventSeriesForm.php b/src/Form/EventSeriesForm.php index 8a83097..5428247 100644 --- a/src/Form/EventSeriesForm.php +++ b/src/Form/EventSeriesForm.php @@ -127,11 +127,11 @@ class EventSeriesForm extends ContentEntityForm { $config = \Drupal::config('recurring_events.eventseries.config'); - $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form'); - /* @var $entity \Drupal\recurring_events\Entity\EventSeries */ $entity = $this->entity; + $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form'); + $form['custom_date']['#states'] = [ 'visible' => [ ':input[name="recur_type"]' => ['value' => 'custom'], @@ -260,8 +260,7 @@ class EventSeriesForm extends ContentEntityForm { /* @var $entity \Drupal\recurring_events\Entity\EventSeries */ $entity = $this->entity; - - $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form'); + $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form'); $trigger = $form_state->getTriggeringElement(); $ignored_triggers = [ diff --git a/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php index 0aee37e..6800388 100644 --- a/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php @@ -11,6 +11,7 @@ use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\HtmlCommand; use Drupal\recurring_events\Plugin\Field\FieldType\ConsecutiveRecurringDate; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'consecutive recurring date' widget. @@ -26,6 +27,7 @@ use Drupal\recurring_events\Plugin\Field\FieldType\ConsecutiveRecurringDate; class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { use RecurringEventsFieldTrait; + use StringTranslationTrait; /** * {@inheritdoc} @@ -42,8 +44,9 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { ], ]; $element['#element_validate'][] = [$this, 'validateThreshold']; + $element['#element_validate'][] = [$this, 'validateForm']; - $element['value']['#title'] = t('Create Events Between'); + $element['value']['#title'] = $this->t('Create Events Between'); $element['value']['#weight'] = 1; $element['value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['value']['#date_date_element'] = 'date'; @@ -55,7 +58,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { 'wrapper' => 'eventseries-edit-form', ]; - $element['end_value']['#title'] = t('And'); + $element['end_value']['#title'] = $this->t('And'); $element['end_value']['#weight'] = 2; $element['end_value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['end_value']['#date_date_element'] = 'date'; @@ -73,7 +76,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $end_time = end($time_keys); $element['time'] = [ '#type' => 'select', - '#title' => t('First Event Starts At'), + '#title' => $this->t('First Event Starts At'), '#options' => $times, '#default_value' => $items[$delta]->time ?: $start_time, '#weight' => 3, @@ -86,7 +89,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['end_time'] = [ '#type' => 'select', - '#title' => t('Final Event Starts At'), + '#title' => $this->t('Final Event Starts At'), '#options' => $times, '#default_value' => $items[$delta]->end_time ?: $end_time, '#weight' => 4, @@ -101,7 +104,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['duration'] = [ '#type' => 'number', - '#title' => t('Event Duration'), + '#title' => $this->t('Event Duration'), '#default_value' => $items[$delta]->duration ?: 5, '#weight' => 5, '#ajax' => [ @@ -113,7 +116,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['duration_units'] = [ '#type' => 'select', - '#title' => t('Event Duration'), + '#title' => $this->t('Event Duration'), '#options' => $units, '#default_value' => $items[$delta]->duration_units ?: 'minute', '#weight' => 6, @@ -147,14 +150,14 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['buffer'] = [ '#type' => 'number', - '#title' => t('Event Buffer'), + '#title' => $this->t('Event Buffer'), '#default_value' => $items[$delta]->buffer ?: 0, '#weight' => 7, ]; $element['buffer_units'] = [ '#type' => 'select', - '#title' => t('Event Buffer'), + '#title' => $this->t('Event Buffer'), '#options' => $units, '#default_value' => $items[$delta]->buffer_units ?: 'minute', '#weight' => 8, @@ -197,7 +200,9 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { */ public function changeDuration(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $form_id = $form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form' ? 'eventseries-edit-form' : 'eventseries-add-form'; + /* @var $entity \Drupal\recurring_events\Entity\EventSeries */ + $entity = $form_state->getformObject()->getEntity(); + $form_id = $form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form' ? 'eventseries-' . $entity->bundle() . '-edit-form' : 'eventseries-' . $entity->bundle() . '-add-form'; $response->addCommand(new HtmlCommand('#' . $form_id, $form)); return $response; } @@ -209,7 +214,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $day_count = $time_count = $total = 0; $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); $form_data = ConsecutiveRecurringDate::convertFormConfigToArray($form_state); - if (!empty($form_data['start_date']) && !empty($form_data['end_date'])) { + if (!empty($form_data['start_date']) && !empty($form_data['end_date']) && !empty($form_data['duration'])) { $day_count = ConsecutiveRecurringDate::findDailyDatesBetweenDates($form_data['start_date'], $form_data['end_date'], TRUE); $time_parts = static::convertTimeTo24hourFormat($form_data['time']); if (!empty($time_parts)) { @@ -251,4 +256,60 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { } } + /** + * Element validate callback to ensure that widget values are valid. + * + * @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 validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'consecutive_recurring_date') { + $values = $form_state->getValue('consecutive_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Consecutive Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['end_time'])) { + $form_state->setError($element['end_time'], $this->t('Please enter an end time')); + } + + if (empty($values['duration']) || $values['duration'] < 1) { + $form_state->setError($element['duration'], $this->t('Please enter a duration greater than 0')); + } + + if (empty($values['duration_units']) || !isset($complete_form['consecutive_recurring_date']['widget'][0]['duration_units']['#options'][$values['duration_units']])) { + $form_state->setError($element['duration_units'], $this->t('Please select a duration units value from the list')); + } + + if (!isset($values['buffer']) || $values['buffer'] === '' || $values['buffer'] < 0) { + $form_state->setError($element['buffer'], $this->t('Please enter a buffer greater than or equal to 0')); + } + + if (empty($values['buffer_units']) || !isset($complete_form['consecutive_recurring_date']['widget'][0]['buffer_units']['#options'][$values['buffer_units']])) { + $form_state->setError($element['buffer_units'], $this->t('Please select a buffer units value from the list')); + } + } + } + } + } diff --git a/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php index 69a9c02..3b9864b 100644 --- a/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php @@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'daily recurring date' widget. @@ -23,6 +24,7 @@ use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait; class DailyRecurringDateWidget extends DateRangeDefaultWidget { use RecurringEventsFieldTrait; + use StringTranslationTrait; /** * {@inheritdoc} @@ -36,15 +38,16 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { ':input[name="recur_type"]' => ['value' => 'daily_recurring_date'], ], ]; + $element['#element_validate'][] = [$this, 'validateForm']; - $element['value']['#title'] = t('Create Events Between'); + $element['value']['#title'] = $this->t('Create Events Between'); $element['value']['#weight'] = 1; $element['value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['value']['#date_date_element'] = 'date'; $element['value']['#date_time_format'] = ''; $element['value']['#date_time_element'] = 'none'; - $element['end_value']['#title'] = t('And'); + $element['end_value']['#title'] = $this->t('And'); $element['end_value']['#weight'] = 2; $element['end_value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['end_value']['#date_date_element'] = 'date'; @@ -54,7 +57,7 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { $times = $this->getTimeOptions(); $element['time'] = [ '#type' => 'select', - '#title' => t('Event Start Time'), + '#title' => $this->t('Event Start Time'), '#options' => $times, '#default_value' => $items[$delta]->time ?: '', '#weight' => 3, @@ -63,7 +66,7 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { $durations = $this->getDurationOptions(); $element['duration'] = [ '#type' => 'select', - '#title' => t('Event Duration'), + '#title' => $this->t('Event Duration'), '#options' => $durations, '#default_value' => $items[$delta]->duration ?: '', '#weight' => 4, @@ -101,4 +104,44 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { return $values; } + /** + * Element validate callback to ensure that widget values are valid. + * + * @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 validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'daily_recurring_date') { + $values = $form_state->getValue('daily_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Daily Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['duration']) || !isset($complete_form['daily_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) { + $form_state->setError($element['duration'], $this->t('Please select a duration from the list')); + } + } + } + } + } diff --git a/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php index 22bef8a..a97f263 100644 --- a/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php @@ -6,6 +6,7 @@ use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'monthly recurring date' widget. @@ -20,6 +21,8 @@ use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; */ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { + use StringTranslationTrait; + /** * {@inheritdoc} */ @@ -31,13 +34,14 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { ':input[name="recur_type"]' => ['value' => 'monthly_recurring_date'], ], ]; + $element['#element_validate'][] = [$this, 'validateForm']; $element['type'] = [ '#type' => 'radios', - '#title' => t('Event Recurrence Schedule'), + '#title' => $this->t('Event Recurrence Schedule'), '#options' => [ - 'weekday' => t('Recur on Day of Week'), - 'monthday' => t('Recur on Day of Month'), + 'weekday' => $this->t('Recur on Day of Week'), + 'monthday' => $this->t('Recur on Day of Month'), ], '#default_value' => $items[$delta]->type ?: '', '#weight' => 5, @@ -45,13 +49,13 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $element['day_occurrence'] = [ '#type' => 'checkboxes', - '#title' => t('Day Occurrence'), + '#title' => $this->t('Day Occurrence'), '#options' => [ - 'first' => t('First'), - 'second' => t('Second'), - 'third' => t('Third'), - 'fourth' => t('Fourth'), - 'last' => t('Last'), + 'first' => $this->t('First'), + 'second' => $this->t('Second'), + 'third' => $this->t('Third'), + 'fourth' => $this->t('Fourth'), + 'last' => $this->t('Last'), ], '#default_value' => $items[$delta]->day_occurrence ? explode(',', $items[$delta]->day_occurrence) : [], '#states' => [ @@ -65,7 +69,7 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $days = $this->getDayOptions(); $element['days'] = [ '#type' => 'checkboxes', - '#title' => t('Days of the Week'), + '#title' => $this->t('Days of the Week'), '#options' => $days, '#default_value' => $items[$delta]->days ? explode(',', $items[$delta]->days) : [], '#states' => [ @@ -79,7 +83,7 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $month_days = $this->getMonthDayOptions(); $element['day_of_month'] = [ '#type' => 'checkboxes', - '#title' => t('Days of the Month'), + '#title' => $this->t('Days of the Month'), '#options' => $month_days, '#default_value' => $items[$delta]->day_of_month ? explode(',', $items[$delta]->day_of_month) : [], '#states' => [ @@ -136,11 +140,82 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $date->modify('+1 day'); } - $days[-1] = t('Last'); + $days[-1] = $this->t('Last'); \Drupal::moduleHandler()->alter('recurring_events_month_days', $days); return $days; } + /** + * Element validate callback to ensure that widget values are valid. + * + * @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 validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'monthly_recurring_date') { + $values = $form_state->getValue('monthly_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Monthly Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['duration']) || !isset($complete_form['monthly_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) { + $form_state->setError($element['duration'], $this->t('Please select a duration from the list')); + } + + if (empty($values['type']) || !isset($complete_form['monthly_recurring_date']['widget'][0]['type']['#options'][$values['type']])) { + $form_state->setError($element['type'], $this->t('Please select an event recurrence schedule type from the list')); + } + else { + switch ($values['type']) { + case 'weekday': + $filtered_day_occurrences = array_filter($values['day_occurrence'], function ($value) { + return !empty($value); + }); + if (empty($values['day_occurrence']) || empty($filtered_day_occurrences)) { + $form_state->setError($element['day_occurrence'], $this->t('Please select a day occurrence from the list')); + } + $filtered_days = array_filter($values['days'], function ($value) { + return !empty($value); + }); + if (empty($values['days']) || empty($filtered_days)) { + $form_state->setError($element['days'], $this->t('Please select week days from the list')); + } + break; + + case 'monthday': + $filtered_days = array_filter($values['day_of_month'], function ($value) { + return !empty($value); + }); + if (empty($values['day_of_month']) || empty($filtered_days)) { + $form_state->setError($element['day_of_month'], $this->t('Please select days of the month from the list')); + } + break; + } + } + } + } + } + } diff --git a/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php index 23dd15f..f09b01c 100644 --- a/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php @@ -5,6 +5,7 @@ namespace Drupal\recurring_events\Plugin\Field\FieldWidget; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Datetime\DrupalDateTime; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'weekly recurring date' widget. @@ -19,6 +20,8 @@ use Drupal\Core\Datetime\DrupalDateTime; */ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget { + use StringTranslationTrait; + /** * {@inheritdoc} */ @@ -31,11 +34,12 @@ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget { ':input[name="recur_type"]' => ['value' => 'weekly_recurring_date'], ], ]; + $element['#element_validate'][] = [$this, 'validateForm']; $days = $this->getDayOptions(); $element['days'] = [ '#type' => 'checkboxes', - '#title' => t('Days of the Week'), + '#title' => $this->t('Days of the Week'), '#options' => $days, '#default_value' => $items[$delta]->days ? explode(',', $items[$delta]->days) : [], '#weight' => 5, @@ -99,4 +103,53 @@ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget { return $days; } + /** + * Element validate callback to ensure that widget values are valid. + * + * @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 validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'weekly_recurring_date') { + $values = $form_state->getValue('weekly_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Weekly Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['duration']) || !isset($complete_form['weekly_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) { + $form_state->setError($element['duration'], $this->t('Please select a duration from the list')); + } + + $filtered_days = array_filter($values['days'], function ($value) { + return !empty($value); + }); + + if (empty($values['days']) || empty($filtered_days)) { + $form_state->setError($element['days'], $this->t('Please select week days from the list')); + } + + } + } + } + } -- GitLab