You are here

class date_api_filter_handler in Date 6

Same name and namespace in other branches
  1. 6.2 includes/date_api_filter_handler.inc \date_api_filter_handler

A flexible, configurable date filter.

This filter allows you to select a granularity of date parts to filter on, such as year, month, day, etc.

Each part can be set to blank to show all values; 'now' to filter for the current value of that part, or a specific value.

An adjustment field is provided that will adjust the selected filter value by something like '+90 days' or '-1 month';

Hierarchy

Expanded class hierarchy of date_api_filter_handler

1 string reference to 'date_api_filter_handler'
date_api_views_data in ./date_api.views.inc
Implementation of hook_views_data()

File

./date_api.views.inc, line 514
Defines date-related Views data and plugins:

View source
class date_api_filter_handler extends views_handler_filter_numeric {
  var $date_handler = NULL;

  // Add a date handler to the filter.
  function construct() {
    parent::construct();
    include_once './' . drupal_get_path('module', 'date_api') . '/date_api_sql.inc';
    $this->date_handler = new views_date_handler();
    $this->date_handler
      ->construct();
    $this->date_handler->granularity = $this->options['granularity'];
    if (isset($this->definition['content_field'])) {
      $this->date_handler->date_type = $this->definition['content_field']['type'];
      $this->content_field = content_fields($this->definition['content_field_name']);
      $this->additional_fields = $this->definition['additional fields'];
    }
  }
  function init(&$view, $options) {
    parent::init($view, $options);
    $handler = $this->date_handler;
    $handler->granularity = $options['granularity'];
    $handler->adjustment_field = $options['adjustment_field'];
  }

  // Set default values for the date filter.
  function options(&$options) {
    parent::options($options);
    $options['granularity'] = 'day';
    $options['adjustment_field'] = 0;

    // We use different values than the parent form, so we must
    // construct our own value options.
    $options['value'] = array();
    foreach (array(
      'value',
      'min',
      'max',
    ) as $prefix) {
      foreach ($this->date_handler
        ->date_parts() as $key => $part) {
        $options['value'][$prefix . $key] = '';
      }
    }
  }

  /**
   * Set the granularity of the date parts to use in the filter.
   */
  function has_extra_options() {
    return TRUE;
  }
  function extra_options_form(&$form, &$form_state) {
    $form['adjustment_field'] = array(
      '#type' => 'radios',
      '#title' => t('Filter type'),
      '#default_value' => $this->options['adjustment_field'],
      '#options' => array(
        0 => t('Date only'),
        1 => t('Both date and adjustment'),
        2 => t('Adjustment only'),
      ),
      '#description' => t('Choose a date to filter on, or use an adjustment field for a value like \'+1 day\'. When you use both date and adjustment, the adjustment will be added to the date. When the adjustment field is used with no date field, the adjustment will be made to the current date.'),
    );
    $form['granularity'] = $this->date_handler
      ->granularity_form($this->options['granularity']);
    $form['granularity']['#description'] = '<p>' . t('Select a granularity for the date filter. For instance, selecting \'day\' will create a filter where you can select the year, month, and day. You will be able to choose a specific value, all values, or \'now\' for each date part in the filter.') . '</p>';
    if (!$this->date_handler
      ->has_tz_support()) {
      $form['granularity']['#description'] .= '<p>' . t('This database does not appear to have native timezone support. Filtering using hour, minute, or second granularity is likely to return incorrect results at least some of the time on systems without native timezone support, so it is recommended to set the granularity to no more than \'day\'.') . '</p>';
    }
  }

  /**
   * Add the selectors to the value form using the date handler.
   */
  function value_form(&$form, &$form_state) {

    // We use different values than the parent form, so we must
    // construct our own form element.
    $form['value'] = array();
    $form['value']['#tree'] = TRUE;
    $which = 'all';
    if (!empty($form['operator'])) {
      $source = $form['operator']['#type'] == 'radios' ? 'radio:options[operator]' : 'edit-options-operator';
    }
    if (!empty($form_state['exposed'])) {
      if (empty($this->options['expose']['operator'])) {

        // exposed and locked.
        $which = in_array($this->operator, $this
          ->operator_values(2)) ? 'minmax' : 'value';
      }
      else {
        $source = 'edit-' . form_clean_id($this->options['expose']['operator']);
      }
    }
    $handler = $this->date_handler;
    if ($which == 'all' || $which == 'value') {
      $form['value'] += $this
        ->date_parts_form('value', $source, $which, $this
        ->operator_values(1));
    }
    if ($which == 'all' || $which == 'minmax') {
      $form['value'] += $this
        ->date_parts_form('min', $source, $which, $this
        ->operator_values(2));
      $form['value'] += $this
        ->date_parts_form('max', $source, $which, $this
        ->operator_values(2));
    }
    $form['value']['description'] = array(
      '#prefix' => '<div class=""><div class="form-item"><div class="description">',
      '#suffix' => '</div></div></div>',
      '#value' => t('Blank values do no filtering, \'now\' filters for the current value.'),
    );
    if ($this->options['adjustment_field'] == 1) {
      $form['value']['description']['#value'] .= t(' \'Adjustment\' filters for an offset like \'+1 day\' from the other values, most useful when used with \'now\'.');
    }
    elseif ($this->options['adjustment_field'] == 2) {
      $form['value']['description']['#value'] = t('\'Adjustment\' filters for an offset like \'+1 day\' from the current time.');
    }
  }

  /**
   * A form element to select date part values.
   *
   * @param string $prefix
   *   A prefix for the date values, 'value', 'min', or 'max'.
   * @param string $source
   *   The operator for this element.
   * @param string $which
   *   Which element to provide, 'all', 'value', or 'minmax'.
   * @param array $operator_values
   *   An array of the allowed operators for this element.
   * @param array $limit
   *   An array of date parts to limit this element to.
   *
   * @return
   *   The form date part element for this instance.
   */
  function date_parts_form($prefix, $source, $which, $operator_values) {
    $prefixname = $prefix == 'value' ? '' : ($prefix == 'min' ? t('From') : t('To'));
    $handler = $this->date_handler;
    $min = $handler
      ->part_info('min');
    $max = $handler
      ->part_info('max');
    $limit = $handler->granularity;
    switch ($this->options['adjustment_field']) {
      case 1:
        $parts = $handler
          ->date_parts($limit) + array(
          'adjustment' => t('Adjustment'),
        );
        $first_item = 'year';
        $last_item = 'adjustment';
        break;
      case 2:
        $parts = array(
          'adjustment' => t('Adjustment'),
        );
        $first_item = 'adjustment';
        $last_item = 'adjustment';
        break;
      default:
        $parts = $handler
          ->date_parts($limit);
        $first_item = 'year';
        $last_item = $this->options['granularity'];
        break;
    }
    foreach ($parts as $key => $name) {
      $options = array(
        '' => '',
        'now' => 'now',
      );
      $type = 'select';
      if ($key == 'year' || $key == 'adjustment') {
        $type = 'textfield';
      }
      $form[$prefix . $key] = array(
        '#title' => t('@type @value', array(
          '@type' => $prefixname,
          '@value' => $name,
        )),
        '#type' => $type,
        '#size' => $key == 'adjustment' ? 20 : ($key == 'year' ? 6 : 1),
        '#default_value' => !empty($this->value[$prefix . $key]) ? $this->value[$prefix . $key] : '',
        '#prefix' => '<div class="views-exposed-date-filter">',
        '#suffix' => '</div>',
      );
      switch ($key) {
        case 'year':
        case 'adjustment':
          break;
        case 'month':
          $form[$prefix . $key]['#options'] = $options + drupal_map_assoc(range(1, 12), 'map_month');
          break;
        default:
          $form[$prefix . $key]['#options'] = $options + drupal_map_assoc(range($min[$key], $max[$key]));
          break;
      }
      if ($type == 'textfield') {
        unset($form[$prefix . $key]['#options']);
      }
      if ($which == 'all') {
        $dependency = array(
          '#process' => array(
            'views_process_dependency',
          ),
          '#dependency' => array(
            $source => $operator_values,
          ),
        );
        $form[$prefix . $key] += $dependency;
      }

      // Add wrappers to force each date grouping to a separate line.
      if ($key == $first_item) {
        $form[$prefix . $key]['#prefix'] = '<div class="clear-block"><div class="views-left-75">' . $form[$prefix . $key]['#prefix'];
      }
      if ($key == $last_item) {
        $form[$prefix . $key]['#suffix'] .= '</div></div>';
      }
    }
    return $form;
  }

  // User the date handler to validate the form.
  function options_validate(&$form, &$form_state) {
    if (!isset($form_state['values']['options']['value'])) {
      return;
    }
    $handler = $this->date_handler;
    $parts = $handler
      ->date_parts();
    $min = $handler
      ->part_info('min');
    $max = $handler
      ->part_info('max');
    $values = $form_state['values']['options']['value'];

    // Validate date values.
    unset($values['offset']);
    foreach ($values as $name => $value) {
      $part = str_replace(array(
        'min',
        'max',
        'value',
      ), '', $value);
      if (!empty($part) && $value != '' && $value != 'now' && ($value < $min[$part] || $value > $max[$part])) {
        form_error($form['value'][$name], t('@value is invalid.', array(
          '@value' => $parts[$part],
        )));
      }
    }
  }

  // Update the summary values to provide
  // meaningful information for each option.
  function admin_summary() {
    $handler = $this->date_handler;
    $output = check_plain($this->operator) . ' ';
    $parts = $handler
      ->date_parts();

    // If the filter is exposed, display the granularity.
    if ($this->options['exposed']) {
      return t('<strong>Exposed</strong> Granularity: @format', array(
        '@format' => $parts[$handler->granularity],
      ));
    }

    // If the filter is not exposed, display the selected values.
    // Check both empty and is_numeric to show all non-blank values,
    // including zero values.
    $min = '';
    $max = '';
    $handler = $this->date_handler;
    $separators = $handler
      ->part_info('sep');
    if (in_array($this->operator, $this
      ->operator_values(2))) {
      foreach ($handler
        ->date_parts($this->value['granularity']) as $key => $part) {
        if (!empty($this->value['min' . $key]) || !empty($this->value['max' . $key]) || is_numeric($this->value['min' . $key]) || is_numeric($this->value['max' . $key])) {
          $min .= $separators[$key] . check_plain($this->value['min' . $key]);
          $max .= $separators[$key] . check_plain($this->value['max' . $key]);
        }
      }
      $output .= t('@min and @max', array(
        '@min' => $min,
        '@max' => $max,
      ));
    }
    else {
      foreach ($handler
        ->date_parts($handler->granularity) as $key => $part) {
        if (!empty($this->value['value' . $key]) || is_numeric($this->value['value' . $key])) {
          $min .= $separators[$key] . check_plain($this->value['value' . $key]);
        }
      }
      $output .= $min;
    }
    return $output;
  }
  function op_between($field) {
    $value = $this
      ->date_filter('min', $field, '>=');
    $value = $this
      ->date_filter('max', $field, '<=');
    return;
  }
  function op_simple($field) {
    $value = $this
      ->date_filter('value', $field, $this->operator);
    return;
  }
  function date_filter($prefix, $field, $operator) {
    $handler = $this->date_handler;
    $granularity = $handler->granularity;
    $parts = $handler
      ->date_parts();
    $filter_parts = $handler
      ->date_parts($handler->granularity);
    $adjustment = 0;
    if (!empty($this->value[$prefix . 'adjustment'])) {
      $adjustment = strtotime($this->value[$prefix . 'adjustment'], 0);

      // See if there are any filters other than the adjustment.
      // If not, compare to NOW() and return.
      if ($this->options['adjustment_field'] == 2) {
        $sql = $handler
          ->sql_field($field, 0) . " {$operator} " . $handler
          ->sql_field('NOW', $adjustment);
        $this->query
          ->add_where($this->options['group'], $sql);
        return;
      }
    }
    $format = '';
    $selected = array();
    $separators = $handler
      ->part_info('sep');
    $formats = $handler
      ->part_info('format');
    foreach ($filter_parts as $key => $part) {
      $sep = $separators[$key];
      $pattern = $key == 'year' ? '%04d' : '%02d';
      if (is_numeric($this->value[$prefix . $key]) || $this->value[$prefix . $key] == 'now') {
        $format .= !empty($format) ? $sep : '';
        $format .= $formats[$key];
      }
      if (is_numeric($this->value[$prefix . $key])) {
        $selected[$key] = sprintf($pattern, check_plain($this->value[$prefix . $key]));
      }
      elseif ($this->value[$prefix . $key] == 'now') {
        $selected[$key] = date($formats[$key]);
      }
      else {

        // When we hit an empty (all values) option in the middle of
        // our date parts, stop and start a new query.
        if ($format > '' && $format != $sep) {
          $date = date_make_date($handler
            ->complete_date($selected));
          $value = date_format($date, $format);
          $sql = $handler
            ->sql_where_format($format, $field, $operator, $value);
          $this->query
            ->add_where($this->options['group'], $sql);
        }
        $format = '';
        $selected = array();
      }
    }
    if ($format > '' && $format != $sep) {
      $date = date_make_date($handler
        ->complete_date($selected));
      $value = date_format($date, $format);
      $sql = $handler
        ->sql_where_format($format, $field, $operator, $value);
      $this->query
        ->add_where($this->options['group'], $sql);
    }
    return;
  }

}

Members