source: sipes/modules_contrib/views/handlers/views_handler_filter.inc @ 59029b2

stableversion-3.0
Last change on this file since 59029b2 was 59029b2, checked in by José Gregorio Puentes <jpuentes@…>, 8 años ago

se actualizo la version del modulo views

  • Propiedad mode establecida a 100644
File size: 20.7 KB
Línea 
1<?php
2/**
3 * @defgroup views_filter_handlers Views' filter handlers
4 * @{
5 * Handlers to tell Views how to filter queries.
6 *
7 * Definition items:
8 * - allow empty: If true, the 'IS NULL' and 'IS NOT NULL' operators become
9 *   available as standard operators.
10 *
11 * Object flags:
12 *  You can set some specific behavior by setting up the following flags on
13 *  your custom class.
14 *
15 * - no_single:
16 *    Disable the possibility to force a single value.
17 * - no_operator:
18 *    Disable the possibility to use operators.
19 * - no_optional:
20 *    Disable the possibility to allow a exposed input to be optional.
21 */
22
23/**
24 * Base class for filters.
25 */
26class views_handler_filter extends views_handler {
27  /**
28   * Contains the actual value of the field,either configured in the views ui
29   * or entered in the exposed filters.
30   */
31  var $value = NULL;
32
33  /**
34   * Contains the operator which is used on the query.
35   */
36  var $operator = '=';
37
38  /**
39   * Provide some extra help to get the operator/value easier to use.
40   *
41   * This likely has to be overridden by filters which are more complex
42   * than simple operator/value.
43   */
44  function init(&$view, $options) {
45    parent::init($view, $options);
46
47    $this->operator = $this->options['operator'];
48    $this->value = $this->options['value'];
49
50    // If there are relationships in the view, allow empty should be true
51    // so that we can do IS NULL checks on items. Not all filters respect
52    // allow empty, but string and numeric do and that covers enough.
53    if ($this->view->display_handler->get_option('relationships')) {
54      $this->definition['allow empty'] = TRUE;
55    }
56  }
57
58  function option_definition() {
59    $options = parent::option_definition();
60
61    $options['operator'] = array('default' => '=');
62    $options['value'] = array('default' => '');
63    $options['group'] = array('default' => '1');
64    $options['exposed'] = array('default' => FALSE);
65    $options['expose'] = array(
66      'contains' => array(
67        'operator' => array('default' => FALSE),
68        'limit_operators' => array('default' => FALSE),
69        'available_operators' => array('default' => array()),
70        'label' => array('default' => '', 'translatable' => TRUE),
71        'use_operator' => array('default' => 0),
72        'operator' => array('default' => ''),
73        'identifier' => array('default' => ''),
74        'optional' => array('default' => 1),
75        'remember' => array('default' => 0),
76        'single' => array('default' => 1),
77      ),
78    );
79
80    return $options;
81  }
82
83  /**
84   * Display the filter on the administrative summary
85   */
86  function admin_summary() {
87    return check_plain((string) $this->operator) . ' ' . check_plain((string) $this->value);
88  }
89
90  /**
91   * Determine if a filter can be exposed.
92   */
93  function can_expose() { return TRUE; }
94
95  /**
96   * Provide the basic form which calls through to subforms.
97   * If overridden, it is best to call through to the parent,
98   * or to at least make sure all of the functions in this form
99   * are called.
100   */
101  function options_form(&$form, &$form_state) {
102    parent::options_form($form, $form_state);
103    if ($this->can_expose()) {
104      $this->show_expose_button($form, $form_state);
105    }
106    $form['op_val_start'] = array('#value' => '<div class="clear-block">');
107    $this->show_operator_form($form, $form_state);
108    $this->show_value_form($form, $form_state);
109    $form['op_val_end'] = array('#value' => '</div>');
110    if ($this->can_expose()) {
111      $this->show_expose_form($form, $form_state);
112    }
113  }
114
115  /**
116   * Simple validate handler
117   */
118  function options_validate(&$form, &$form_state) {
119    $this->operator_validate($form, $form_state);
120    $this->value_validate($form, $form_state);
121    if (!empty($this->options['exposed'])) {
122      $this->expose_validate($form, $form_state);
123    }
124
125  }
126
127  /**
128   * Simple submit handler
129   */
130  function options_submit($form, &$form_state) {
131    unset($form_state['values']['expose_button']); // don't store this.
132    $this->operator_submit($form, $form_state);
133    $this->value_submit($form, $form_state);
134    if (!empty($this->options['exposed'])) {
135      if (!empty($form_state['values']['options']['expose']['limit_operators'])) {
136        $form_state['values']['options']['expose']['available_operators'] = array_filter($form_state['values']['options']['expose']['available_operators']);
137      }
138      else {
139        $form_state['values']['options']['expose']['available_operators'] = array();
140      }
141      $this->expose_submit($form, $form_state);
142      if (empty($form_state['values']['options']['expose']['use_operator'])) {
143        $form_state['values']['options']['expose']['limit_operators'] = array();
144      }
145    }
146  }
147
148  /**
149   * Shortcut to display the operator form.
150   */
151  function show_operator_form(&$form, &$form_state) {
152    $this->operator_form($form, $form_state);
153    $form['operator']['#prefix'] = '<div class="views-left-30">';
154    $form['operator']['#suffix'] = '</div>';
155  }
156
157  /**
158   * Provide a form for setting the operator.
159   *
160   * This may be overridden by child classes, and it must
161   * define $form['operator'];
162   */
163  function operator_form(&$form, &$form_state) {
164    $options = $this->operator_options();
165    if (!empty($options)) {
166      $limit = array_filter($this->options['expose']['available_operators']);
167      if (!empty($this->options['expose']['limit_operators']) && count($limit)) {
168        foreach ($options as $key => $value) {
169          if (!isset($limit[$key])) {
170            unset($options[$key]);
171          }
172        }
173      }
174      $form['operator'] = array(
175        '#type' => count($options) < 10 ? 'radios' : 'select',
176        '#title' => t('Operator'),
177        '#default_value' => $this->operator,
178        '#options' => $options,
179      );
180    }
181  }
182
183  /**
184   * Provide a list of options for the default operator form.
185   * Should be overridden by classes that don't override operator_form
186   */
187  function operator_options() { return array(); }
188
189  /**
190   * Validate the operator form.
191   */
192  function operator_validate($form, &$form_state) { }
193
194  /**
195   * Perform any necessary changes to the form values prior to storage.
196   * There is no need for this function to actually store the data.
197   */
198  function operator_submit($form, &$form_state) { }
199
200  /**
201   * Shortcut to display the value form.
202   */
203  function show_value_form(&$form, &$form_state) {
204    $this->value_form($form, $form_state);
205    if (empty($this->no_operator)) {
206      $form['value']['#prefix'] = '<div class="views-right-70">' . (isset($form['value']['#prefix']) ? $form['value']['#prefix'] : '');
207      $form['value']['#suffix'] = (isset($form['value']['#suffix']) ? $form['value']['#suffix'] : '') . '</div>';
208    }
209  }
210
211  /**
212   * Provide a form for setting options.
213   *
214   * This should be overridden by all child classes and it must
215   * define $form['value']
216   */
217  function value_form(&$form, &$form_state) { $form['value'] = array(); }
218
219  /**
220   * Validate the options form.
221   */
222  function value_validate($form, &$form_state) { }
223
224  /**
225   * Perform any necessary changes to the form values prior to storage.
226   * There is no need for this function to actually store the data.
227   */
228  function value_submit($form, &$form_state) { }
229
230  /**
231   * Handle the 'left' side fo the exposed options form.
232   */
233  function expose_form_left(&$form, &$form_state) {
234    if (!empty($form['operator']['#type'])) {
235      $form['expose']['use_operator'] = array(
236        '#type' => 'checkbox',
237        '#title' => t('Unlock operator'),
238        '#description' => t('When checked, the operator will be exposed to the user'),
239        '#default_value' => !empty($this->options['expose']['use_operator']),
240      );
241      $form['expose']['operator'] = array(
242        '#type' => 'textfield',
243        '#default_value' => $this->options['expose']['operator'],
244        '#title' => t('Operator identifier'),
245        '#size' => 40,
246        '#description' => t('This will appear in the URL after the ? to identify this operator.'),
247        '#process' => array('views_process_dependency'),
248        '#dependency' => array(
249          'edit-options-expose-use-operator' => array(1)
250        ),
251      );
252      $form['expose']['limit_operators'] = array(
253        '#type' => 'checkbox',
254        '#title' => t('Limit operators'),
255        '#description' => t('When checked, the operator will be exposed to the user'),
256        '#default_value' => !empty($this->options['expose']['limit_operators']),
257        '#process' => array('views_process_dependency'),
258        '#dependency' => array(
259          'edit-options-expose-use-operator' => array(1)
260        ),
261        '#description' => t('Restrict which operators will be available to select in the exposed operator form.'),
262      );
263      $operator_options = $this->operator_options();
264      if (count($operator_options)) {
265        $form['expose']['available_operators'] = array(
266          '#type' => 'checkboxes',
267          '#title' => t('Limit the exposed operators'),
268          '#default_value' => $this->options['expose']['available_operators'],
269          '#prefix' => '<div id="edit-options-expose-available-operators-wrapper"><div id = "edit-options-expose-available-operators">',
270          '#suffix' => '</div></div>',
271          '#description' => t('Select which operators will be available to select in the exposed operator form. If none is selected, all the operators listed here will be used.'),
272          '#options' => $operator_options,
273          '#process' => array('expand_checkboxes', 'views_process_dependency'),
274          '#dependency' => array(
275            'edit-options-expose-limit-operators' => array(1)
276          ),
277        );
278      }
279    }
280    else {
281      $form['expose']['operator'] = array(
282        '#type' => 'value',
283        '#value' => '',
284      );
285    }
286
287    $form['expose']['identifier'] = array(
288      '#type' => 'textfield',
289      '#default_value' => $this->options['expose']['identifier'],
290      '#title' => t('Filter identifier'),
291      '#size' => 40,
292      '#description' => t('This will appear in the URL after the ? to identify this filter. Cannot be blank.'),
293    );
294    $form['expose']['label'] = array(
295      '#type' => 'textfield',
296      '#default_value' => $this->options['expose']['label'],
297      '#title' => t('Label'),
298      '#size' => 40,
299    );
300  }
301
302  /**
303   * Handle the 'right' side fo the exposed options form.
304   */
305  function expose_form_right(&$form, &$form_state) {
306    if (empty($this->no_optional)) {
307      $form['expose']['optional'] = array(
308        '#type' => 'checkbox',
309        '#title' => t('Optional'),
310        '#description' => t('This exposed filter is optional and will have added options to allow it not to be set.'),
311        '#default_value' => $this->options['expose']['optional'],
312      );
313    }
314    else {
315      $form['expose']['optional'] = array(
316        '#type' => 'value',
317        '#value' => FALSE,
318      );
319    }
320    if (empty($this->no_single)) {
321      $form['expose']['single'] = array(
322        '#type' => 'checkbox',
323        '#title' => t('Force single'),
324        '#description' => t('Force this exposed filter to accept only one option.'),
325        '#default_value' => $this->options['expose']['single'],
326      );
327    }
328    $form['expose']['remember'] = array(
329      '#type' => 'checkbox',
330      '#title' => t('Remember'),
331      '#description' => t('Remember the last setting the user gave this filter.'),
332      '#default_value' => $this->options['expose']['remember'],
333    );
334  }
335
336  /**
337   * Validate the options form.
338   */
339  function expose_validate($form, &$form_state) {
340    if (empty($this->options['expose']['identifier'])) {
341      if (empty($form_state['values']['options']['expose']['identifier'])) {
342        form_error($form['expose']['identifier'], t('The identifier is required if the filter is exposed.'));
343      }
344    }
345
346    if (!empty($form_state['values']['options']['expose']['identifier']) && $form_state['values']['options']['expose']['identifier'] == 'value') {
347      form_error($form['expose']['identifier'], t('This identifier is not allowed.'));
348    }
349
350    if (!$this->view->display_handler->is_identifier_unique($form_state['id'], $form_state['values']['options']['expose']['identifier'])) {
351      form_error($form['expose']['identifier'], t('This identifier is used by another handler.'));
352    }
353  }
354
355  /**
356   * Provide default options for exposed filters.
357   */
358  function expose_options() {
359    $this->options['expose'] = array(
360      'use_operator' => FALSE,
361      'operator' => $this->options['id'] . '_op',
362      'identifier' => $this->options['id'],
363      'label' => $this->ui_name(),
364      'remember' => FALSE,
365      'single' => TRUE,
366      'optional' => TRUE,
367    );
368  }
369
370  /**
371   * Render our chunk of the exposed filter form when selecting
372   *
373   * You can override this if it doesn't do what you expect.
374   */
375  function exposed_form(&$form, &$form_state) {
376    if (empty($this->options['exposed'])) {
377      return;
378    }
379
380    // Build the exposed form, when its based on an operator.
381    if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator'])) {
382      $operator = $this->options['expose']['operator'];
383      $this->operator_form($form, $form_state);
384      $form[$operator] = $form['operator'];
385
386      if (isset($form[$operator]['#title'])) {
387        unset($form[$operator]['#title']);
388      }
389
390      $this->exposed_translate($form[$operator], 'operator');
391
392      unset($form['operator']);
393    }
394
395    // Build the form and set the value based on the identifier.
396    if (!empty($this->options['expose']['identifier'])) {
397      $value = $this->options['expose']['identifier'];
398      $this->value_form($form, $form_state);
399      $form[$value] = $form['value'];
400
401      if (isset($form[$value]['#title']) && !empty($form[$value]['#type']) && $form[$value]['#type'] != 'checkbox') {
402        unset($form[$value]['#title']);
403      }
404
405      $this->exposed_translate($form[$value], 'value');
406
407      if (!empty($form['#type']) && ($form['#type'] == 'checkboxes' || ($form['#type'] == 'select' && !empty($form['#multiple'])))) {
408        unset($form[$value]['#default_value']);
409      }
410
411      if (!empty($form['#type']) && $form['#type'] == 'select' && empty($form['#multiple'])) {
412        $form[$value]['#default_value'] = 'All';
413      }
414
415      if ($value != 'value') {
416        unset($form['value']);
417      }
418    }
419  }
420
421  /**
422   * Make some translations to a form item to make it more suitable to
423   * exposing.
424   */
425  function exposed_translate(&$form, $type) {
426    if (!isset($form['#type'])) {
427      return;
428    }
429
430    if ($form['#type'] == 'radios') {
431      $form['#type'] = 'select';
432    }
433    // Checkboxes don't work so well in exposed forms due to GET conversions.
434    if ($form['#type'] == 'checkboxes') {
435      if (empty($form['#no_convert']) || !empty($this->options['expose']['single'])) {
436        $form['#type'] = 'select';
437      }
438      if (empty($this->options['expose']['single'])) {
439        $form['#multiple'] = TRUE;
440      }
441    }
442    if (!empty($this->options['expose']['single']) && isset($form['#multiple'])) {
443      unset($form['#multiple']);
444      $form['#size'] = NULL;
445    }
446
447    if ($type == 'value' && empty($this->no_optional) && !empty($this->options['expose']['optional']) && $form['#type'] == 'select' && empty($form['#multiple'])) {
448      $any_label = variable_get('views_exposed_filter_any_label', 'old_any') == 'old_any' ? '<Any>' : t('- Any -');
449      $form['#options'] = array('All' => $any_label) + $form['#options'];
450      $form['#default_value'] = 'All';
451
452      if (empty($this->options['expose']['optional'])) {
453        $form['#required'] = TRUE;
454      }
455    }
456  }
457
458  /**
459   * Tell the renderer about our exposed form. This only needs to be
460   * overridden for particularly complex forms. And maybe not even then.
461   *
462   * @return array|null
463   *   An array with the following keys:
464   *   - operator: The $form key of the operator. Set to NULL if no operator.
465   *   - value: The $form key of the value. Set to NULL if no value.
466   *   - label: The label to use for this piece.
467   */
468  function exposed_info() {
469    if (empty($this->options['exposed'])) {
470      return;
471    }
472
473    return array(
474      'operator' => $this->options['expose']['operator'],
475      'value' => $this->options['expose']['identifier'],
476      'label' => $this->options['expose']['label'],
477    );
478  }
479
480  /**
481   * Check to see if input from the exposed filters should change
482   * the behavior of this filter.
483   */
484  function accept_exposed_input($input) {
485    if (empty($this->options['exposed'])) {
486      return TRUE;
487    }
488
489
490    if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator']) && isset($input[$this->options['expose']['operator']])) {
491      $this->operator = $input[$this->options['expose']['operator']];
492    }
493
494    if (!empty($this->options['expose']['identifier'])) {
495      $value = $input[$this->options['expose']['identifier']];
496
497      // Various ways to check for the absence of optional input.
498      if (!empty($this->options['expose']['optional'])) {
499
500        if (($this->operator == 'empty' || $this->operator == 'not empty') && $value === '') {
501          $value = ' ';
502        }
503
504        if ($this->operator != 'empty' && $this->operator != 'not empty') {
505          if ($value == 'All' || $value === array()) {
506            return FALSE;
507          }
508        }
509
510        if (!empty($this->no_single) && $value === '') {
511          return FALSE;
512        }
513      }
514
515
516      if (isset($value)) {
517        $this->value = $value;
518        if (empty($this->no_single) && !empty($this->options['expose']['single'])) {
519          $this->value = array($value);
520        }
521      }
522      else {
523        return FALSE;
524      }
525    }
526
527    return TRUE;
528  }
529
530  function store_exposed_input($input, $status) {
531    if (empty($this->options['exposed']) || empty($this->options['expose']['identifier'])) {
532      return TRUE;
533    }
534
535    if (empty($this->options['expose']['remember'])) {
536      return;
537    }
538
539    // Figure out which display id is responsible for the filters, so we
540    // know where to look for session stored values.
541    $display_id = ($this->view->display_handler->is_defaulted('filters')) ? 'default' : $this->view->current_display;
542
543    // shortcut test.
544    $operator = !empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator']);
545
546    // false means that we got a setting that means to recuse ourselves,
547    // so we should erase whatever happened to be there.
548    if (!$status && isset($_SESSION['views'][$this->view->name][$display_id])) {
549      $session = &$_SESSION['views'][$this->view->name][$display_id];
550      if ($operator && isset($session[$this->options['expose']['operator']])) {
551        unset($session[$this->options['expose']['operator']]);
552      }
553
554      if (isset($session[$this->options['expose']['identifier']])) {
555        unset($session[$this->options['expose']['identifier']]);
556      }
557    }
558
559    if ($status) {
560      if (!isset($_SESSION['views'][$this->view->name][$display_id])) {
561        $_SESSION['views'][$this->view->name][$display_id] = array();
562      }
563
564      $session = &$_SESSION['views'][$this->view->name][$display_id];
565
566      if ($operator && isset($input[$this->options['expose']['operator']])) {
567        $session[$this->options['expose']['operator']] = $input[$this->options['expose']['operator']];
568      }
569
570      $session[$this->options['expose']['identifier']] = $input[$this->options['expose']['identifier']];
571    }
572  }
573
574  /**
575   * Add this filter to the query.
576   *
577   * Due to the nature of fapi, the value and the operator have an unintended
578   * level of indirection. You will find them in $this->operator
579   * and $this->value respectively.
580   */
581  function query() {
582    $this->ensure_my_table();
583    $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field " . $this->operator . " '%s'", $this->value);
584  }
585
586  /**
587   * Can this filter be used in OR groups?
588   *
589   * Some filters have complicated where clauses that cannot be easily used
590   * with OR groups. Some filters must also use HAVING which also makes
591   * them not groupable. These filters will end up in a special group
592   * if OR grouping is in use.
593   *
594   * @return bool
595   */
596   function can_group() {
597     return TRUE;
598   }
599}
600
601
602/**
603 * A special handler to take the place of missing or broken handlers.
604 *
605 * @ingroup views_filter_handlers
606 */
607class views_handler_filter_broken extends views_handler_filter {
608  function ui_name($short = FALSE) {
609    return t('Broken/missing handler');
610  }
611
612  function ensure_my_table() { /* No table to ensure! */ }
613  function query() { /* No query to run */ }
614  function options_form(&$form, &$form_state) {
615    $form['markup'] = array(
616      '#prefix' => '<div class="form-item description">',
617      '#value' => t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.'),
618    );
619  }
620
621  /**
622   * Determine if the handler is considered 'broken'
623   */
624  function broken() { return TRUE; }
625}
626
627
628/**
629 * @}
630 */
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.