Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / views / src / Plugin / views / filter / NumericFilter.php
1 <?php
2
3 namespace Drupal\views\Plugin\views\filter;
4
5 use Drupal\Core\Form\FormStateInterface;
6
7 /**
8  * Simple filter to handle greater than/less than filters
9  *
10  * @ingroup views_filter_handlers
11  *
12  * @ViewsFilter("numeric")
13  */
14 class NumericFilter extends FilterPluginBase {
15
16   protected $alwaysMultiple = TRUE;
17
18   protected function defineOptions() {
19     $options = parent::defineOptions();
20
21     $options['value'] = [
22       'contains' => [
23         'min' => ['default' => ''],
24         'max' => ['default' => ''],
25         'value' => ['default' => ''],
26       ],
27     ];
28
29     $options['expose']['contains']['placeholder'] = ['default' => ''];
30     $options['expose']['contains']['min_placeholder'] = ['default' => ''];
31     $options['expose']['contains']['max_placeholder'] = ['default' => ''];
32
33     return $options;
34   }
35
36   /**
37    * {@inheritdoc}
38    */
39   public function defaultExposeOptions() {
40     parent::defaultExposeOptions();
41     $this->options['expose']['min_placeholder'] = NULL;
42     $this->options['expose']['max_placeholder'] = NULL;
43     $this->options['expose']['placeholder'] = NULL;
44   }
45
46   /**
47    * {@inheritdoc}
48    */
49   public function buildExposeForm(&$form, FormStateInterface $form_state) {
50     parent::buildExposeForm($form, $form_state);
51
52     $form['expose']['min_placeholder'] = [
53       '#type' => 'textfield',
54       '#default_value' => $this->options['expose']['min_placeholder'],
55       '#title' => $this->t('Min placeholder'),
56       '#size' => 40,
57       '#description' => $this->t('Hint text that appears inside the Min field when empty.'),
58     ];
59     $form['expose']['max_placeholder'] = [
60       '#type' => 'textfield',
61       '#default_value' => $this->options['expose']['max_placeholder'],
62       '#title' => $this->t('Max placeholder'),
63       '#size' => 40,
64       '#description' => $this->t('Hint text that appears inside the Max field when empty.'),
65     ];
66     // Setup #states for all operators with two value.
67     $states = [[':input[name="options[expose][use_operator]"]' => ['checked' => TRUE]]];
68     foreach ($this->operatorValues(2) as $operator) {
69       $states[] = [
70         ':input[name="options[operator]"]' => ['value' => $operator],
71       ];
72     }
73     $form['expose']['min_placeholder']['#states']['visible'] = $states;
74     $form['expose']['max_placeholder']['#states']['visible'] = $states;
75
76     $form['expose']['placeholder'] = [
77       '#type' => 'textfield',
78       '#default_value' => $this->options['expose']['placeholder'],
79       '#title' => $this->t('Placeholder'),
80       '#size' => 40,
81       '#description' => $this->t('Hint text that appears inside the field when empty.'),
82     ];
83     // Setup #states for all operators with one value.
84     $form['expose']['placeholder']['#states']['visible'] = [[':input[name="options[expose][use_operator]"]' => ['checked' => TRUE]]];
85     foreach ($this->operatorValues(1) as $operator) {
86       $form['expose']['placeholder']['#states']['visible'][] = [
87         ':input[name="options[operator]"]' => ['value' => $operator],
88       ];
89     }
90   }
91
92   public function operators() {
93     $operators = [
94       '<' => [
95         'title' => $this->t('Is less than'),
96         'method' => 'opSimple',
97         'short' => $this->t('<'),
98         'values' => 1,
99       ],
100       '<=' => [
101         'title' => $this->t('Is less than or equal to'),
102         'method' => 'opSimple',
103         'short' => $this->t('<='),
104         'values' => 1,
105       ],
106       '=' => [
107         'title' => $this->t('Is equal to'),
108         'method' => 'opSimple',
109         'short' => $this->t('='),
110         'values' => 1,
111       ],
112       '!=' => [
113         'title' => $this->t('Is not equal to'),
114         'method' => 'opSimple',
115         'short' => $this->t('!='),
116         'values' => 1,
117       ],
118       '>=' => [
119         'title' => $this->t('Is greater than or equal to'),
120         'method' => 'opSimple',
121         'short' => $this->t('>='),
122         'values' => 1,
123       ],
124       '>' => [
125         'title' => $this->t('Is greater than'),
126         'method' => 'opSimple',
127         'short' => $this->t('>'),
128         'values' => 1,
129       ],
130       'between' => [
131         'title' => $this->t('Is between'),
132         'method' => 'opBetween',
133         'short' => $this->t('between'),
134         'values' => 2,
135       ],
136       'not between' => [
137         'title' => $this->t('Is not between'),
138         'method' => 'opBetween',
139         'short' => $this->t('not between'),
140         'values' => 2,
141       ],
142       'regular_expression' => [
143         'title' => $this->t('Regular expression'),
144         'short' => $this->t('regex'),
145         'method' => 'opRegex',
146         'values' => 1,
147       ],
148     ];
149
150     // if the definition allows for the empty operator, add it.
151     if (!empty($this->definition['allow empty'])) {
152       $operators += [
153         'empty' => [
154           'title' => $this->t('Is empty (NULL)'),
155           'method' => 'opEmpty',
156           'short' => $this->t('empty'),
157           'values' => 0,
158         ],
159         'not empty' => [
160           'title' => $this->t('Is not empty (NOT NULL)'),
161           'method' => 'opEmpty',
162           'short' => $this->t('not empty'),
163           'values' => 0,
164         ],
165       ];
166     }
167
168     return $operators;
169   }
170
171   /**
172    * Provide a list of all the numeric operators
173    */
174   public function operatorOptions($which = 'title') {
175     $options = [];
176     foreach ($this->operators() as $id => $info) {
177       $options[$id] = $info[$which];
178     }
179
180     return $options;
181   }
182
183   protected function operatorValues($values = 1) {
184     $options = [];
185     foreach ($this->operators() as $id => $info) {
186       if ($info['values'] == $values) {
187         $options[] = $id;
188       }
189     }
190
191     return $options;
192   }
193
194   /**
195    * Provide a simple textfield for equality
196    */
197   protected function valueForm(&$form, FormStateInterface $form_state) {
198     $form['value']['#tree'] = TRUE;
199
200     // We have to make some choices when creating this as an exposed
201     // filter form. For example, if the operator is locked and thus
202     // not rendered, we can't render dependencies; instead we only
203     // render the form items we need.
204     $which = 'all';
205     if (!empty($form['operator'])) {
206       $source = ':input[name="options[operator]"]';
207     }
208
209     if ($exposed = $form_state->get('exposed')) {
210       $identifier = $this->options['expose']['identifier'];
211
212       if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
213         // exposed and locked.
214         $which = in_array($this->operator, $this->operatorValues(2)) ? 'minmax' : 'value';
215       }
216       else {
217         $source = ':input[name="' . $this->options['expose']['operator_id'] . '"]';
218       }
219     }
220
221     $user_input = $form_state->getUserInput();
222     if ($which == 'all') {
223       $form['value']['value'] = [
224         '#type' => 'textfield',
225         '#title' => !$exposed ? $this->t('Value') : '',
226         '#size' => 30,
227         '#default_value' => $this->value['value'],
228       ];
229       if (!empty($this->options['expose']['placeholder'])) {
230         $form['value']['value']['#attributes']['placeholder'] = $this->options['expose']['placeholder'];
231       }
232       // Setup #states for all operators with one value.
233       foreach ($this->operatorValues(1) as $operator) {
234         $form['value']['value']['#states']['visible'][] = [
235           $source => ['value' => $operator],
236         ];
237       }
238       if ($exposed && !isset($user_input[$identifier]['value'])) {
239         $user_input[$identifier]['value'] = $this->value['value'];
240         $form_state->setUserInput($user_input);
241       }
242     }
243     elseif ($which == 'value') {
244       // When exposed we drop the value-value and just do value if
245       // the operator is locked.
246       $form['value'] = [
247         '#type' => 'textfield',
248         '#title' => !$exposed ? $this->t('Value') : '',
249         '#size' => 30,
250         '#default_value' => $this->value['value'],
251       ];
252       if (!empty($this->options['expose']['placeholder'])) {
253         $form['value']['#attributes']['placeholder'] = $this->options['expose']['placeholder'];
254       }
255       if ($exposed && !isset($user_input[$identifier])) {
256         $user_input[$identifier] = $this->value['value'];
257         $form_state->setUserInput($user_input);
258       }
259     }
260
261     if ($which == 'all' || $which == 'minmax') {
262       $form['value']['min'] = [
263         '#type' => 'textfield',
264         '#title' => !$exposed ? $this->t('Min') : $this->exposedInfo()['label'],
265         '#size' => 30,
266         '#default_value' => $this->value['min'],
267         '#description' => !$exposed ? '' : $this->exposedInfo()['description'],
268       ];
269       if (!empty($this->options['expose']['min_placeholder'])) {
270         $form['value']['min']['#attributes']['placeholder'] = $this->options['expose']['min_placeholder'];
271       }
272       $form['value']['max'] = [
273         '#type' => 'textfield',
274         '#title' => !$exposed ? $this->t('And max') : $this->t('And'),
275         '#size' => 30,
276         '#default_value' => $this->value['max'],
277       ];
278       if (!empty($this->options['expose']['max_placeholder'])) {
279         $form['value']['max']['#attributes']['placeholder'] = $this->options['expose']['max_placeholder'];
280       }
281       if ($which == 'all') {
282         $states = [];
283         // Setup #states for all operators with two values.
284         foreach ($this->operatorValues(2) as $operator) {
285           $states['#states']['visible'][] = [
286             $source => ['value' => $operator],
287           ];
288         }
289         $form['value']['min'] += $states;
290         $form['value']['max'] += $states;
291       }
292       if ($exposed && !isset($user_input[$identifier]['min'])) {
293         $user_input[$identifier]['min'] = $this->value['min'];
294       }
295       if ($exposed && !isset($user_input[$identifier]['max'])) {
296         $user_input[$identifier]['max'] = $this->value['max'];
297       }
298
299       if (!isset($form['value'])) {
300         // Ensure there is something in the 'value'.
301         $form['value'] = [
302           '#type' => 'value',
303           '#value' => NULL,
304         ];
305       }
306     }
307   }
308
309   public function query() {
310     $this->ensureMyTable();
311     $field = "$this->tableAlias.$this->realField";
312
313     $info = $this->operators();
314     if (!empty($info[$this->operator]['method'])) {
315       $this->{$info[$this->operator]['method']}($field);
316     }
317   }
318
319   protected function opBetween($field) {
320     if ($this->operator == 'between') {
321       $this->query->addWhere($this->options['group'], $field, [$this->value['min'], $this->value['max']], 'BETWEEN');
322     }
323     else {
324       $this->query->addWhere($this->options['group'], $field, [$this->value['min'], $this->value['max']], 'NOT BETWEEN');
325     }
326   }
327
328   protected function opSimple($field) {
329     $this->query->addWhere($this->options['group'], $field, $this->value['value'], $this->operator);
330   }
331
332   protected function opEmpty($field) {
333     if ($this->operator == 'empty') {
334       $operator = "IS NULL";
335     }
336     else {
337       $operator = "IS NOT NULL";
338     }
339
340     $this->query->addWhere($this->options['group'], $field, NULL, $operator);
341   }
342
343   /**
344    * Filters by a regular expression.
345    *
346    * @param string $field
347    *   The expression pointing to the queries field, for example "foo.bar".
348    */
349   protected function opRegex($field) {
350     $this->query->addWhere($this->options['group'], $field, $this->value['value'], 'REGEXP');
351   }
352
353   public function adminSummary() {
354     if ($this->isAGroup()) {
355       return $this->t('grouped');
356     }
357     if (!empty($this->options['exposed'])) {
358       return $this->t('exposed');
359     }
360
361     $options = $this->operatorOptions('short');
362     $output = $options[$this->operator];
363     if (in_array($this->operator, $this->operatorValues(2))) {
364       $output .= ' ' . $this->t('@min and @max', ['@min' => $this->value['min'], '@max' => $this->value['max']]);
365     }
366     elseif (in_array($this->operator, $this->operatorValues(1))) {
367       $output .= ' ' . $this->value['value'];
368     }
369     return $output;
370   }
371
372   /**
373    * Do some minor translation of the exposed input
374    */
375   public function acceptExposedInput($input) {
376     if (empty($this->options['exposed'])) {
377       return TRUE;
378     }
379
380     // rewrite the input value so that it's in the correct format so that
381     // the parent gets the right data.
382     if (!empty($this->options['expose']['identifier'])) {
383       $value = &$input[$this->options['expose']['identifier']];
384       if (!is_array($value)) {
385         $value = [
386           'value' => $value,
387         ];
388       }
389     }
390
391     $rc = parent::acceptExposedInput($input);
392
393     if (empty($this->options['expose']['required'])) {
394       // We have to do some of our own checking for non-required filters.
395       $info = $this->operators();
396       if (!empty($info[$this->operator]['values'])) {
397         switch ($info[$this->operator]['values']) {
398           case 1:
399             if ($value['value'] === '') {
400               return FALSE;
401             }
402             break;
403           case 2:
404             if ($value['min'] === '' && $value['max'] === '') {
405               return FALSE;
406             }
407             break;
408         }
409       }
410     }
411
412     return $rc;
413   }
414
415 }