85fda9ba536dddb99fde72445ad2f13fbfa59cda
[yaffs-website] / web / core / modules / datetime_range / src / Plugin / Field / FieldWidget / DateRangeWidgetBase.php
1 <?php
2
3 namespace Drupal\datetime_range\Plugin\Field\FieldWidget;
4
5 use Drupal\Core\Datetime\DrupalDateTime;
6 use Drupal\Core\Field\FieldItemListInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
9 use Drupal\datetime\Plugin\Field\FieldWidget\DateTimeWidgetBase;
10 use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
11
12 /**
13  * Base class for the 'daterange_*' widgets.
14  */
15 class DateRangeWidgetBase extends DateTimeWidgetBase {
16
17   /**
18    * {@inheritdoc}
19    */
20   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
21     $element = parent::formElement($items, $delta, $element, $form, $form_state);
22
23     // Wrap all of the select elements with a fieldset.
24     $element['#theme_wrappers'][] = 'fieldset';
25
26     $element['#element_validate'][] = [$this, 'validateStartEnd'];
27     $element['value']['#title'] = $this->t('Start date');
28
29     $element['end_value'] = [
30       '#title' => $this->t('End date'),
31     ] + $element['value'];
32
33     if ($items[$delta]->start_date) {
34       /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */
35       $start_date = $items[$delta]->start_date;
36       $element['value']['#default_value'] = $this->createDefaultValue($start_date, $element['value']['#date_timezone']);
37     }
38
39     if ($items[$delta]->end_date) {
40       /** @var \Drupal\Core\Datetime\DrupalDateTime $end_date */
41       $end_date = $items[$delta]->end_date;
42       $element['end_value']['#default_value'] = $this->createDefaultValue($end_date, $element['end_value']['#date_timezone']);
43     }
44
45     return $element;
46   }
47
48   /**
49    * {@inheritdoc}
50    */
51   public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
52     // The widget form element type has transformed the value to a
53     // DrupalDateTime object at this point. We need to convert it back to the
54     // storage timezone and format.
55     foreach ($values as &$item) {
56       if (!empty($item['value']) && $item['value'] instanceof DrupalDateTime) {
57         /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */
58         $start_date = $item['value'];
59         switch ($this->getFieldSetting('datetime_type')) {
60           case DateRangeItem::DATETIME_TYPE_DATE:
61             $format = DateTimeItemInterface::DATE_STORAGE_FORMAT;
62             break;
63
64           case DateRangeItem::DATETIME_TYPE_ALLDAY:
65             // All day fields start at midnight on the starting date, but are
66             // stored like datetime fields, so we need to adjust the time.
67             // This function is called twice, so to prevent a double conversion
68             // we need to explicitly set the timezone.
69             $start_date->setTimeZone(timezone_open(drupal_get_user_timezone()));
70             $start_date->setTime(0, 0, 0);
71             $format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
72             break;
73
74           default:
75             $format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
76             break;
77         }
78         // Adjust the date for storage.
79         $start_date->setTimezone(new \DateTimezone(DateTimeItemInterface::STORAGE_TIMEZONE));
80         $item['value'] = $start_date->format($format);
81       }
82
83       if (!empty($item['end_value']) && $item['end_value'] instanceof DrupalDateTime) {
84         /** @var \Drupal\Core\Datetime\DrupalDateTime $end_date */
85         $end_date = $item['end_value'];
86         switch ($this->getFieldSetting('datetime_type')) {
87           case DateRangeItem::DATETIME_TYPE_DATE:
88             $format = DateTimeItemInterface::DATE_STORAGE_FORMAT;
89             break;
90
91           case DateRangeItem::DATETIME_TYPE_ALLDAY:
92             // All day fields end at midnight on the end date, but are
93             // stored like datetime fields, so we need to adjust the time.
94             // This function is called twice, so to prevent a double conversion
95             // we need to explicitly set the timezone.
96             $end_date->setTimeZone(timezone_open(drupal_get_user_timezone()));
97             $end_date->setTime(23, 59, 59);
98             $format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
99             break;
100
101           default:
102             $format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
103             break;
104         }
105         // Adjust the date for storage.
106         $end_date->setTimezone(new \DateTimezone(DateTimeItemInterface::STORAGE_TIMEZONE));
107         $item['end_value'] = $end_date->format($format);
108       }
109     }
110
111     return $values;
112   }
113
114   /**
115    * #element_validate callback to ensure that the start date <= the end date.
116    *
117    * @param array $element
118    *   An associative array containing the properties and children of the
119    *   generic form element.
120    * @param \Drupal\Core\Form\FormStateInterface $form_state
121    *   The current state of the form.
122    * @param array $complete_form
123    *   The complete form structure.
124    */
125   public function validateStartEnd(array &$element, FormStateInterface $form_state, array &$complete_form) {
126     $start_date = $element['value']['#value']['object'];
127     $end_date = $element['end_value']['#value']['object'];
128
129     if ($start_date instanceof DrupalDateTime && $end_date instanceof DrupalDateTime) {
130       if ($start_date->getTimestamp() !== $end_date->getTimestamp()) {
131         $interval = $start_date->diff($end_date);
132         if ($interval->invert === 1) {
133           $form_state->setError($element, $this->t('The @title end date cannot be before the start date', ['@title' => $element['#title']]));
134         }
135       }
136     }
137   }
138
139 }