dbb573fcd497047da099b9d35ea314e95826f166
[yaffs-website] / web / core / modules / views / src / Plugin / views / filter / Date.php
1 <?php
2
3 namespace Drupal\views\Plugin\views\filter;
4
5 use Drupal\Core\Form\FormStateInterface;
6
7 /**
8  * Filter to handle dates stored as a timestamp.
9  *
10  * @ingroup views_filter_handlers
11  *
12  * @ViewsFilter("date")
13  */
14 class Date extends NumericFilter {
15
16   protected function defineOptions() {
17     $options = parent::defineOptions();
18
19     // value is already set up properly, we're just adding our new field to it.
20     $options['value']['contains']['type']['default'] = 'date';
21
22     return $options;
23   }
24
25   /**
26    * Add a type selector to the value form
27    */
28   protected function valueForm(&$form, FormStateInterface $form_state) {
29     if (!$form_state->get('exposed')) {
30       $form['value']['type'] = [
31         '#type' => 'radios',
32         '#title' => $this->t('Value type'),
33         '#options' => [
34           'date' => $this->t('A date in any machine readable format. CCYY-MM-DD HH:MM:SS is preferred.'),
35           'offset' => $this->t('An offset from the current time such as "@example1" or "@example2"', ['@example1' => '+1 day', '@example2' => '-2 hours -30 minutes']),
36         ],
37         '#default_value' => !empty($this->value['type']) ? $this->value['type'] : 'date',
38       ];
39     }
40     parent::valueForm($form, $form_state);
41   }
42
43   public function validateOptionsForm(&$form, FormStateInterface $form_state) {
44     parent::validateOptionsForm($form, $form_state);
45
46     if (!empty($this->options['exposed']) && $form_state->isValueEmpty(['options', 'expose', 'required'])) {
47       // Who cares what the value is if it's exposed and non-required.
48       return;
49     }
50
51     $this->validateValidTime($form['value'], $form_state, $form_state->getValue(['options', 'operator']), $form_state->getValue(['options', 'value']));
52   }
53
54   public function validateExposed(&$form, FormStateInterface $form_state) {
55     if (empty($this->options['exposed'])) {
56       return;
57     }
58
59     if (empty($this->options['expose']['required'])) {
60       // Who cares what the value is if it's exposed and non-required.
61       return;
62     }
63
64     $value = &$form_state->getValue($this->options['expose']['identifier']);
65     if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
66       $operator = &$form_state->getValue($this->options['expose']['operator_id']);
67     }
68     else {
69       $operator = $this->operator;
70     }
71
72     $this->validateValidTime($this->options['expose']['identifier'], $form_state, $operator, $value);
73
74   }
75
76   /**
77    * Validate that the time values convert to something usable.
78    */
79   public function validateValidTime(&$form, FormStateInterface $form_state, $operator, $value) {
80     $operators = $this->operators();
81
82     if ($operators[$operator]['values'] == 1) {
83       $convert = strtotime($value['value']);
84       if (!empty($form['value']) && ($convert == -1 || $convert === FALSE)) {
85         $form_state->setError($form['value'], $this->t('Invalid date format.'));
86       }
87     }
88     elseif ($operators[$operator]['values'] == 2) {
89       $min = strtotime($value['min']);
90       if ($min == -1 || $min === FALSE) {
91         $form_state->setError($form['min'], $this->t('Invalid date format.'));
92       }
93       $max = strtotime($value['max']);
94       if ($max == -1 || $max === FALSE) {
95         $form_state->setError($form['max'], $this->t('Invalid date format.'));
96       }
97     }
98   }
99
100   /**
101    * {@inheritdoc}
102    */
103   protected function hasValidGroupedValue(array $group) {
104     if (!is_array($group['value']) || empty($group['value'])) {
105       return FALSE;
106     }
107
108     // Special case when validating grouped date filters because the
109     // $group['value'] array contains the type of filter (date or offset) and
110     // therefore the number of items the comparison has to be done against is
111     // one greater.
112     $operators = $this->operators();
113     $expected = $operators[$group['operator']]['values'] + 1;
114     $actual = count(array_filter($group['value'], 'static::arrayFilterZero'));
115
116     return $actual == $expected;
117   }
118
119   public function acceptExposedInput($input) {
120     if (empty($this->options['exposed'])) {
121       return TRUE;
122     }
123
124     // Store this because it will get overwritten.
125     $type = NULL;
126     if ($this->isAGroup()) {
127       if (is_array($this->group_info)) {
128         $type = $this->group_info['type'];
129       }
130     }
131     else {
132       $type = $this->value['type'];
133     }
134     $rc = parent::acceptExposedInput($input);
135
136     // Restore what got overwritten by the parent.
137     if (!is_null($type)) {
138       $this->value['type'] = $type;
139     }
140
141     // Don't filter if value(s) are empty.
142     $operators = $this->operators();
143     if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
144       $operator = $input[$this->options['expose']['operator_id']];
145     }
146     else {
147       $operator = $this->operator;
148     }
149
150     if ($operators[$operator]['values'] == 1) {
151       if ($this->value['value'] == '') {
152         return FALSE;
153       }
154     }
155     else {
156       if ($this->value['min'] == '' || $this->value['max'] == '') {
157         return FALSE;
158       }
159     }
160
161     return $rc;
162   }
163
164   protected function opBetween($field) {
165     $a = intval(strtotime($this->value['min'], 0));
166     $b = intval(strtotime($this->value['max'], 0));
167
168     if ($this->value['type'] == 'offset') {
169       $a = '***CURRENT_TIME***' . sprintf('%+d', $a); // keep sign
170       $b = '***CURRENT_TIME***' . sprintf('%+d', $b); // keep sign
171     }
172     // This is safe because we are manually scrubbing the values.
173     // It is necessary to do it this way because $a and $b are formulas when using an offset.
174     $operator = strtoupper($this->operator);
175     $this->query->addWhereExpression($this->options['group'], "$field $operator $a AND $b");
176   }
177
178   protected function opSimple($field) {
179     $value = intval(strtotime($this->value['value'], 0));
180     if (!empty($this->value['type']) && $this->value['type'] == 'offset') {
181       $value = '***CURRENT_TIME***' . sprintf('%+d', $value); // keep sign
182     }
183     // This is safe because we are manually scrubbing the value.
184     // It is necessary to do it this way because $value is a formula when using an offset.
185     $this->query->addWhereExpression($this->options['group'], "$field $this->operator $value");
186   }
187
188 }