Projet

Général

Profil

Paste
Télécharger (13,4 ko) Statistiques
| Branche: | Révision:

root / htmltest / sites / all / modules / views / handlers / views_handler_filter_in_operator.inc @ 4543c6c7

1
<?php
2

    
3
/**
4
 * @file
5
 * Definition of views_handler_filter_in_operator.
6
 */
7

    
8
/**
9
 * Simple filter to handle matching of multiple options selectable via checkboxes
10
 *
11
 * Definition items:
12
 * - options callback: The function to call in order to generate the value options. If omitted, the options 'Yes' and 'No' will be used.
13
 * - options arguments: An array of arguments to pass to the options callback.
14
 *
15
 * @ingroup views_filter_handlers
16
 */
17
class views_handler_filter_in_operator extends views_handler_filter {
18
  var $value_form_type = 'checkboxes';
19

    
20
  /**
21
   * @var array
22
   * Stores all operations which are available on the form.
23
   */
24
  var $value_options = NULL;
25

    
26
  function construct() {
27
    parent::construct();
28
    $this->value_title = t('Options');
29
    $this->value_options = NULL;
30
  }
31

    
32
  /**
33
   * Child classes should be used to override this function and set the
34
   * 'value options', unless 'options callback' is defined as a valid function
35
   * or static public method to generate these values.
36
   *
37
   * This can use a guard to be used to reduce database hits as much as
38
   * possible.
39
   *
40
   * @return
41
   *   Return the stored values in $this->value_options if someone expects it.
42
   */
43
  function get_value_options() {
44
    if (isset($this->value_options)) {
45
      return;
46
    }
47

    
48
    if (isset($this->definition['options callback']) && is_callable($this->definition['options callback'])) {
49
      if (isset($this->definition['options arguments']) && is_array($this->definition['options arguments'])) {
50
        $this->value_options = call_user_func_array($this->definition['options callback'], $this->definition['options arguments']);
51
      }
52
      else {
53
        $this->value_options = call_user_func($this->definition['options callback']);
54
      }
55
    }
56
    else {
57
      $this->value_options = array(t('Yes'), t('No'));
58
    }
59

    
60
    return $this->value_options;
61
  }
62

    
63
  function expose_options() {
64
    parent::expose_options();
65
    $this->options['expose']['reduce'] = FALSE;
66
  }
67

    
68
  function expose_form(&$form, &$form_state) {
69
    parent::expose_form($form, $form_state);
70
    $form['expose']['reduce'] = array(
71
      '#type' => 'checkbox',
72
      '#title' => t('Limit list to selected items'),
73
      '#description' => t('If checked, the only items presented to the user will be the ones selected here.'),
74
      '#default_value' => !empty($this->options['expose']['reduce']), // safety
75
    );
76
  }
77

    
78
  function option_definition() {
79
    $options = parent::option_definition();
80

    
81
    $options['operator']['default'] = 'in';
82
    $options['value']['default'] = array();
83
    $options['expose']['contains']['reduce'] = array('default' => FALSE, 'bool' => TRUE);
84

    
85
    return $options;
86
  }
87

    
88
  /**
89
   * This kind of construct makes it relatively easy for a child class
90
   * to add or remove functionality by overriding this function and
91
   * adding/removing items from this array.
92
   */
93
  function operators() {
94
    $operators = array(
95
      'in' => array(
96
        'title' => t('Is one of'),
97
        'short' => t('in'),
98
        'short_single' => t('='),
99
        'method' => 'op_simple',
100
        'values' => 1,
101
      ),
102
      'not in' => array(
103
        'title' => t('Is not one of'),
104
        'short' => t('not in'),
105
        'short_single' => t('<>'),
106
        'method' => 'op_simple',
107
        'values' => 1,
108
      ),
109
    );
110
    // if the definition allows for the empty operator, add it.
111
    if (!empty($this->definition['allow empty'])) {
112
      $operators += array(
113
        'empty' => array(
114
          'title' => t('Is empty (NULL)'),
115
          'method' => 'op_empty',
116
          'short' => t('empty'),
117
          'values' => 0,
118
        ),
119
        'not empty' => array(
120
          'title' => t('Is not empty (NOT NULL)'),
121
          'method' => 'op_empty',
122
          'short' => t('not empty'),
123
          'values' => 0,
124
        ),
125
      );
126
    }
127

    
128
    return $operators;
129
  }
130

    
131
  /**
132
   * Build strings from the operators() for 'select' options
133
   */
134
  function operator_options($which = 'title') {
135
    $options = array();
136
    foreach ($this->operators() as $id => $info) {
137
      $options[$id] = $info[$which];
138
    }
139

    
140
    return $options;
141
  }
142

    
143
  function operator_values($values = 1) {
144
    $options = array();
145
    foreach ($this->operators() as $id => $info) {
146
      if (isset($info['values']) && $info['values'] == $values) {
147
        $options[] = $id;
148
      }
149
    }
150

    
151
    return $options;
152
  }
153

    
154
  function value_form(&$form, &$form_state) {
155
    $form['value'] = array();
156
    $options = array();
157

    
158
    if (empty($form_state['exposed'])) {
159
      // Add a select all option to the value form.
160
      $options = array('all' => t('Select all'));
161
    }
162

    
163
    $this->get_value_options();
164
    $options += $this->value_options;
165
    $default_value = (array) $this->value;
166

    
167
    $which = 'all';
168
    if (!empty($form['operator'])) {
169
      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
170
    }
171
    if (!empty($form_state['exposed'])) {
172
      $identifier = $this->options['expose']['identifier'];
173

    
174
      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
175
        // exposed and locked.
176
        $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
177
      }
178
      else {
179
        $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
180
      }
181

    
182
      if (!empty($this->options['expose']['reduce'])) {
183
        $options = $this->reduce_value_options();
184

    
185
        if (!empty($this->options['expose']['multiple']) && empty($this->options['expose']['required'])) {
186
          $default_value = array();
187
        }
188
      }
189

    
190
      if (empty($this->options['expose']['multiple'])) {
191
        if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
192
          $default_value = 'All';
193
        }
194
        elseif (empty($default_value)) {
195
          $keys = array_keys($options);
196
          $default_value = array_shift($keys);
197
        }
198
        else {
199
          $copy = $default_value;
200
          $default_value = array_shift($copy);
201
        }
202
      }
203
    }
204

    
205
    if ($which == 'all' || $which == 'value') {
206
      $form['value'] = array(
207
        '#type' => $this->value_form_type,
208
        '#title' => $this->value_title,
209
        '#options' => $options,
210
        '#default_value' => $default_value,
211
        // These are only valid for 'select' type, but do no harm to checkboxes.
212
        '#multiple' => TRUE,
213
        '#size' => count($options) > 8 ? 8 : count($options),
214
      );
215
      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
216
        $form_state['input'][$identifier] = $default_value;
217
      }
218

    
219
      if ($which == 'all') {
220
        if (empty($form_state['exposed']) && (in_array($this->value_form_type, array('checkbox', 'checkboxes', 'radios', 'select')))) {
221
          $form['value']['#prefix'] = '<div id="edit-options-value-wrapper">';
222
          $form['value']['#suffix'] = '</div>';
223
        }
224
        $form['value']['#dependency'] = array($source => $this->operator_values(1));
225
      }
226
    }
227
  }
228

    
229
  /**
230
   * When using exposed filters, we may be required to reduce the set.
231
   */
232
  function reduce_value_options($input = NULL) {
233
    if (!isset($input)) {
234
      $input = $this->value_options;
235
    }
236

    
237
    // Because options may be an array of strings, or an array of mixed arrays
238
    // and strings (optgroups) or an array of objects, we have to
239
    // step through and handle each one individually.
240
    $options = array();
241
    foreach ($input as $id => $option) {
242
      if (is_array($option)) {
243
        $options[$id] = $this->reduce_value_options($option);
244
        continue;
245
      }
246
      elseif (is_object($option)) {
247
        $keys = array_keys($option->option);
248
        $key = array_shift($keys);
249
        if (isset($this->options['value'][$key])) {
250
          $options[$id] = $option;
251
        }
252
      }
253
      elseif (isset($this->options['value'][$id])) {
254
        $options[$id] = $option;
255
      }
256
    }
257
    return $options;
258
  }
259

    
260
  function accept_exposed_input($input) {
261
    // A very special override because the All state for this type of
262
    // filter could have a default:
263
    if (empty($this->options['exposed'])) {
264
      return TRUE;
265
    }
266

    
267
    // If this is non-multiple and non-required, then this filter will
268
    // participate, but using the default settings, *if* 'limit is true.
269
    if (empty($this->options['expose']['multiple']) && empty($this->options['expose']['required']) && !empty($this->options['expose']['limit'])) {
270
      $identifier = $this->options['expose']['identifier'];
271
      if ($input[$identifier] == 'All') {
272
        return TRUE;
273
      }
274
    }
275

    
276
    return parent::accept_exposed_input($input);
277
  }
278

    
279
  function value_submit($form, &$form_state) {
280
    // Drupal's FAPI system automatically puts '0' in for any checkbox that
281
    // was not set, and the key to the checkbox if it is set.
282
    // Unfortunately, this means that if the key to that checkbox is 0,
283
    // we are unable to tell if that checkbox was set or not.
284

    
285
    // Luckily, the '#value' on the checkboxes form actually contains
286
    // *only* a list of checkboxes that were set, and we can use that
287
    // instead.
288

    
289
    $form_state['values']['options']['value'] = $form['value']['#value'];
290
  }
291

    
292
  function admin_summary() {
293
    if ($this->is_a_group()) {
294
      return t('grouped');
295
    }
296
    if (!empty($this->options['exposed'])) {
297
      return t('exposed');
298
    }
299
    $info = $this->operators();
300

    
301
    $this->get_value_options();
302

    
303
    if (!is_array($this->value)) {
304
      return;
305
    }
306

    
307
    $operator = check_plain($info[$this->operator]['short']);
308
    $values = '';
309
    if (in_array($this->operator, $this->operator_values(1))) {
310
      // Remove every element which is not known.
311
      foreach ($this->value as $value) {
312
        if (!isset($this->value_options[$value])) {
313
          unset($this->value[$value]);
314
        }
315
      }
316
      // Choose different kind of ouput for 0, a single and multiple values.
317
      if (count($this->value) == 0) {
318
        $values = t('Unknown');
319
      }
320
      else if (count($this->value) == 1) {
321
        // If any, use the 'single' short name of the operator instead.
322
        if (isset($info[$this->operator]['short_single'])) {
323
          $operator = check_plain($info[$this->operator]['short_single']);
324
        }
325

    
326
        $keys = $this->value;
327
        $value = array_shift($keys);
328
        if (isset($this->value_options[$value])) {
329
          $values = check_plain($this->value_options[$value]);
330
        }
331
        else {
332
          $values = '';
333
        }
334
      }
335
      else {
336
        foreach ($this->value as $value) {
337
          if ($values !== '') {
338
            $values .= ', ';
339
          }
340
          if (drupal_strlen($values) > 8) {
341
            $values .= '...';
342
            break;
343
          }
344
          if (isset($this->value_options[$value])) {
345
            $values .= check_plain($this->value_options[$value]);
346
          }
347
        }
348
      }
349
    }
350

    
351
    return $operator . (($values !== '') ? ' ' . $values : '');
352
  }
353

    
354
  function query() {
355
    $info = $this->operators();
356
    if (!empty($info[$this->operator]['method'])) {
357
      $this->{$info[$this->operator]['method']}();
358
    }
359
  }
360

    
361
  function op_simple() {
362
    if (empty($this->value)) {
363
      return;
364
    }
365
    $this->ensure_my_table();
366

    
367
    // We use array_values() because the checkboxes keep keys and that can cause
368
    // array addition problems.
369
    $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", array_values($this->value), $this->operator);
370
  }
371

    
372
  function op_empty() {
373
    $this->ensure_my_table();
374
    if ($this->operator == 'empty') {
375
      $operator = "IS NULL";
376
    }
377
    else {
378
      $operator = "IS NOT NULL";
379
    }
380

    
381
    $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", NULL, $operator);
382
  }
383

    
384
  function validate() {
385
    $this->get_value_options();
386
    $errors = array();
387

    
388
    // If the operator is an operator which doesn't require a value, there is
389
    // no need for additional validation.
390
    if (in_array($this->operator, $this->operator_values(0))) {
391
      return array();
392
    }
393

    
394
    if (!in_array($this->operator, $this->operator_values(1))) {
395
      $errors[] = t('The operator is invalid on filter: @filter.', array('@filter' => $this->ui_name(TRUE)));
396
    }
397
    if (is_array($this->value)) {
398
      if (!isset($this->value_options)) {
399
        // Don't validate if there are none value options provided, for example for special handlers.
400
        return $errors;
401
      }
402
      if ($this->options['exposed'] && !$this->options['expose']['required'] && empty($this->value)) {
403
        // Don't validate if the field is exposed and no default value is provided.
404
        return $errors;
405
      }
406

    
407
      // Some filter_in_operator usage uses optgroups forms, so flatten it.
408
      $flat_options = form_options_flatten($this->value_options, TRUE);
409

    
410
      // Remove every element which is not known.
411
      foreach ($this->value as $value) {
412
        if (!isset($flat_options[$value])) {
413
          unset($this->value[$value]);
414
        }
415
      }
416
      // Choose different kind of ouput for 0, a single and multiple values.
417
      if (count($this->value) == 0) {
418
        $errors[] = t('No valid values found on filter: @filter.', array('@filter' => $this->ui_name(TRUE)));
419
      }
420
    }
421
    elseif (!empty($this->value) && ($this->operator == 'in' || $this->operator == 'not in')) {
422
      $errors[] = t('The value @value is not an array for @operator on filter: @filter', array('@value' => views_var_export($this->value), '@operator' => $this->operator, '@filter' => $this->ui_name(TRUE)));
423
    }
424
    return $errors;
425
  }
426
}