You are here

class availability_calendar_handler_filter_availability in Availability Calendars 7.4

Same name and namespace in other branches
  1. 7.5 views/availability_calendar_handler_filter_availability.inc \availability_calendar_handler_filter_availability
  2. 7.3 availability_calendar_handler_filter_availability.inc \availability_calendar_handler_filter_availability

Views handler to filter on availability.

This filter inherits from views_handler_filter as inheriting from views_handler_filter_numeric or views_handler_filter_date did not turn out to be a lot easier.

This filter allows to filter on availability by accepting the following values:

  • 1 date (for availability at that given date).
  • Begin and end date (end date inclusive).
  • Arrival and departure date (departure date not inclusive).
  • Start date and duration.

Hierarchy

Expanded class hierarchy of availability_calendar_handler_filter_availability

1 string reference to 'availability_calendar_handler_filter_availability'
availability_calendar_field_views_data_alter in views/availability_calendar.views.inc
Implements hook_field_views_data_alter().

File

views/availability_calendar_handler_filter_availability.inc, line 16

View source
class availability_calendar_handler_filter_availability extends views_handler_filter {
  public static $instance;
  public function __construct() {
    self::$instance = $this;
    $this->always_multiple = TRUE;
    module_load_include('inc', 'availability_calendar', 'availability_calendar');
  }
  public function option_definition() {
    $options = parent::option_definition();
    $options['value'] = array(
      'contains' => array(
        'from' => array(
          'default' => '',
        ),
        'to' => array(
          'default' => '',
        ),
        'to1' => array(
          'default' => '',
        ),
        'duration' => array(
          'default' => '',
        ),
      ),
    );
    $options['operator'] = array(
      'default' => 'from_duration',
    );
    return $options;
  }
  public function operators() {
    $operators = array(
      'at' => array(
        'title' => t('At (date)'),
        'method' => 'op_at',
        'summary' => t('at %from'),
        'values' => array(
          'from',
        ),
      ),
      'from_to' => array(
        'title' => t('From begin up to and including end'),
        'method' => 'op_from_to',
        'summary' => t('From %from to %to'),
        'values' => array(
          'from',
          'to',
        ),
      ),
      'from_to1' => array(
        'title' => t('From arrival to departure'),
        'method' => 'op_from_to1',
        'summary' => t('From %from to %to1'),
        'values' => array(
          'from',
          'to1',
        ),
      ),
      'from_duration' => array(
        'title' => t('From begin during duration'),
        'method' => 'op_from_duration',
        'summary' => t('From %from during %duration days'),
        'values' => array(
          'from',
          'duration',
        ),
      ),
    );
    return $operators;
  }

  /**
   * Provides a list of all the availability operators, optionally restricted
   * to only the given property of the operators.
   */
  public function operator_options($which = 'title') {
    $options = array();
    foreach ($this
      ->operators() as $id => $operator) {
      $options[$id] = $operator[$which];
    }
    return $options;
  }
  public function operators_by_value($value) {
    $options = array();
    foreach ($this
      ->operators() as $id => $operator) {
      if (in_array($value, $operator['values'])) {
        $options[] = $id;
      }
    }
    return $options;
  }

  /**
   * Add validation and date popup(s) to the value form.
   */
  public function value_form(&$form, &$form_state) {
    $form['value']['#tree'] = TRUE;
    if (empty($form_state['exposed'])) {

      // We're in Views edit mode self. Add validator here. When we're in an
      // exposed form, validation will go via exposed_validate().
      $form['value']['#element_validate'][] = 'availability_calendar_handler_filter_availability_validate_value';
    }

    // Determine values to add and their dependencies.
    $dependency_source = NULL;
    if (!empty($form_state['exposed']) && (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id']))) {

      // Exposed form with operator not exposed: only add values for the
      // set operator.
      $operators = $this
        ->operators();
      $values = $operators[$this->operator]['values'];
    }
    else {

      // Views UI.
      $values = array(
        'from',
        'to',
        'to1',
        'duration',
      );
      if (!empty($form['operator'])) {
        $dependency_source = $form['operator']['#type'] === 'radios' ? 'radio:options[operator]' : 'edit-options-operator';
      }
    }

    // Add value fields.
    if (in_array('from', $values)) {
      $form['value']['from'] = array(
        '#type' => 'textfield',
        '#title' => $this->operator === 'at' ? t('At') : ($this->operator === 'from_to1' ? t('Arrival date') : t('Start date')),
        '#size' => 12,
        '#default_value' => $this->value['from'],
      );
      if (module_exists('date_popup')) {
        $this
          ->change_element_into_date_popup($form['value']['from'], 0);
      }
      else {
        $date_example = availability_calendar_format_entry_date(new DateTime());
        $form['value']['from']['#description'] = t('E.g., @date', array(
          '@date' => $date_example,
        ));
      }
      if ($dependency_source !== NULL) {
        $form['value']['from']['#dependency'] = array(
          $dependency_source => $this
            ->operators_by_value('from'),
        );
      }
    }
    if (in_array('to', $values)) {
      $form['value']['to'] = array(
        '#type' => 'textfield',
        '#title' => t('End date'),
        '#size' => 12,
        '#default_value' => $this->value['to'],
      );
      if (module_exists('date_popup')) {
        $this
          ->change_element_into_date_popup($form['value']['to'], 0);
        $this
          ->couple_date_popups();
      }
      else {
        $date = new DateTime();
        $date
          ->modify('+6 days');
        $date_example = availability_calendar_format_entry_date($date);
        $form['value']['to']['#description'] = t('E.g., @date', array(
          '@date' => $date_example,
        ));
      }
      if ($dependency_source !== NULL) {
        $form['value']['to']['#dependency'] = array(
          $dependency_source => $this
            ->operators_by_value('to'),
        );
      }
    }
    if (in_array('to1', $values)) {
      $form['value']['to1'] = array(
        '#type' => 'textfield',
        '#title' => t('Departure date'),
        '#size' => 12,
        '#default_value' => $this->value['to1'],
      );
      if (module_exists('date_popup')) {
        $this
          ->change_element_into_date_popup($form['value']['to1'], 1);
        $this
          ->couple_date_popups();
      }
      else {
        $date = new DateTime();
        $date
          ->modify('+7 days');
        $date_example = availability_calendar_format_entry_date($date);
        $form['value']['to1']['#description'] = t('E.g., @date', array(
          '@date' => $date_example,
        ));
      }
      if ($dependency_source !== NULL) {
        $form['value']['to1']['#dependency'] = array(
          $dependency_source => $this
            ->operators_by_value('to1'),
        );
      }
    }
    if (in_array('duration', $values)) {
      $options = array(
        0 => t('- Select duration -'),
      );
      for ($i = 1; $i <= 28; $i++) {
        if ($i % 7 === 0) {
          $options[$i] = format_plural($i / 7, '1 week', '@count weeks');
        }
        else {
          if ($i <= 20) {
            if ($this->definition['allocation_type'] === AC_ALLOCATION_TYPE_FULLDAY) {
              $options[$i] = format_plural($i, '1 day', '@count days');
            }
            else {
              $options[$i] = format_plural($i, '1 night', '@count nights');
            }
          }
        }
      }
      $form['value']['duration'] = array(
        '#type' => 'select',
        '#title' => t('Duration'),
        '#options' => $options,
        '#default_value' => $this->value['duration'],
      );
      if ($dependency_source !== NULL) {
        $form['value']['duration']['#dependency'] = array(
          $dependency_source => $this
            ->operators_by_value('duration'),
        );
      }
    }
  }

  /**
   * Changes a (text) form element into a date popup element.
   *
   * @param array $element
   * @param int $offset
   */
  protected function change_element_into_date_popup(&$element, $offset) {
    $element['#type'] = 'date_popup';
    $element['#date_label_position'] = 'none';
    $element['#date_type'] = 'DATE_ISO';
    $element['#date_format'] = variable_get('date_format_availability_calendar_date_entry', AC_DATE_ENTRY);

    // @todo: firstDay and maxDate based on field (formatter) settings?
    $element['#datepicker_options'] = array(
      'firstDay' => variable_get('date_first_day', 6),
      'minDate' => $offset,
      'maxDate' => '+24m',
    );
  }

  /**
   * Adds the necessary js to couple date popups to select a date range.
   */
  protected function couple_date_popups() {
    static $added = FALSE;
    if (!$added) {
      $added = TRUE;
      drupal_add_js(drupal_get_path('module', 'availability_calendar') . '/views/availability_calendar_handler_filter_availability.js');
    }
  }

  /**
   * Validates our part of the exposed form.
   *
   * Overrides @see views_handler::exposed_validate().
   */
  public function exposed_validate(&$form, &$form_state) {
    if (empty($this->options['exposed'])) {
      return;
    }
    $this
      ->validate_value($form[$this->options['expose']['identifier']], $form_state);
  }

  /**
   * Validate that the values convert to something usable.
   */
  public function validate_value(&$element, $form_state) {
    if (empty($form_state['exposed'])) {

      // In Views UI, the value is required if the filter is not exposed,
      // otherwise we don't validate at all (so people can place "help texts" in
      // the inputs.)
      if ($form_state['values']['options']['expose_button']['checkbox']['checkbox']) {
        return;
      }
      $required = FALSE;
      $operator = $form_state['values']['options']['operator'];
    }
    else {

      // In exposed form, values are required if "Required" was checked.
      $required = (bool) $this->options['expose']['required'];
      $operator = empty($this->options['expose']['use_operator']) ? $this->operator : $form_state['values'][$this->options['expose']['operator_id']];
    }
    $operators = $this
      ->operators();
    $values = empty($operator) ? array(
      'from',
      'to',
      'to1',
      'duration',
    ) : $operators[$operator]['values'];

    // Set time to midnight as other dates are also set to that time.
    $today = new DateTime();
    $today
      ->setTime(0, 0, 0);
    $value = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
    $from_valid = FALSE;
    if (in_array('from', $values) && array_key_exists('from', $value)) {
      $from_valid = $this
        ->validate_valid_time_1($element['from'], $value['from'], $required, $today, t('Only future availability can be searched.'));
    }
    if (in_array('to', $values) && array_key_exists('to', $value)) {
      $this
        ->validate_valid_time_1($element['to'], $value['to'], $required || $from_valid instanceof DateTime, $from_valid, t('The end date should be on or after the start date.'));
    }
    if (in_array('to1', $values) && array_key_exists('to1', $value)) {
      $this
        ->validate_valid_time_1($element['to1'], $value['to1'], $required || $from_valid instanceof DateTime, $from_valid, t('The departure date should be after the arrival date.'));
    }
    if (in_array('duration', $values) && array_key_exists('duration', $value)) {
      $this
        ->validate_valid_duration($element['duration'], $value['duration'], $required || $from_valid instanceof DateTime);
    }
  }

  /**
   * @param array $element
   * @param array|DateTime $value
   * @param bool $required
   * @param DateTime|null $minimum
   * @param string $minimum_error_message
   *
   * @return DateTime|false
   */
  protected function validate_valid_time_1(&$element, $value, $required, $minimum, $minimum_error_message) {
    $valid = TRUE;

    // If date popup is enabled, the value will be an array (with a date and
    // time component).
    if (is_array($value)) {
      $value = $value['date'];
    }
    if (empty($value) || $value === $element['#default_value']) {
      if ($required) {
        form_error($element, t('Field %field is required.', array(
          '%field' => $element['#title'],
        )));
        $valid = FALSE;
      }
    }
    else {
      if (($value = availability_calendar_parse_entry_date($value)) === FALSE) {
        form_error($element, t('Invalid date format.'));
        $valid = FALSE;
      }
      else {
        if ($minimum instanceof DateTime && $value < $minimum) {
          form_error($element, $minimum_error_message);
          $valid = FALSE;
        }
      }
    }
    return $valid ? $value : $valid;
  }
  protected function validate_valid_duration(&$element, $value, $required) {
    $valid = TRUE;
    if (empty($value)) {
      if ($required) {
        form_error($element, t('Field %field is required.', array(
          '%field' => $element['#title'],
        )));
        $valid = FALSE;
      }
    }
    else {
      if (!is_int($value) && !ctype_digit($value) || $value <= 0) {
        form_error($element, t('Duration must be a positive number of days.'));
        $valid = FALSE;
      }
    }
    return $valid;
  }

  /**
   * Check to see if input from the exposed filters should change
   * the behavior of this filter.
   */
  public function accept_exposed_input($input) {
    if (empty($this->options['exposed'])) {
      return TRUE;
    }
    if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id']) && isset($input[$this->options['expose']['operator_id']])) {

      // Fetch operator from form (instead of from $this object)
      $this->operator = $input[$this->options['expose']['operator_id']];
    }
    if (!empty($this->options['expose']['identifier'])) {

      // Fetch value from form (instead of from $this object)
      $this->value = $input[$this->options['expose']['identifier']];

      // Check if the values are filled in, if not, we don't want to change the
      // query. A value is filled in if it is not empty and does not equal an
      // invalid default value. Validation will already have failed if the value
      // does not equal the default value but is invalid. So we just check if
      // the values are valid.
      $operators = $this
        ->operators();
      $values = $operators[$this->operator]['values'];
      foreach ($values as $value_name) {
        if (empty($this->value[$value_name])) {
          return FALSE;
        }
        else {
          if ($value_name === 'duration') {
            if (!is_int($this->value[$value_name]) && !ctype_digit($this->value[$value_name]) || $this->value[$value_name] <= 0) {
              return FALSE;
            }
          }
          else {
            if (availability_calendar_parse_entry_date($this->value[$value_name]) === FALSE) {
              return FALSE;
            }
          }
        }
      }
    }
    return TRUE;
  }
  public function query() {
    $this
      ->ensure_my_table();
    $operators = $this
      ->operators();
    if (isset($operators[$this->operator]['method'])) {
      $this
        ->{$operators[$this->operator]['method']}();
    }
  }
  protected function op_at() {
    $this->value['duration'] = 1;
    $this
      ->op_from_duration();
  }
  protected function op_from_to() {
    $this
      ->build_query(availability_calendar_parse_entry_date($this->value['from']), availability_calendar_parse_entry_date($this->value['to']));
  }
  protected function op_from_to1() {
    $from = availability_calendar_parse_entry_date($this->value['from']);
    $to = availability_calendar_parse_entry_date($this->value['to1']);
    if ($from instanceof DateTime && $to instanceof DateTime) {

      // Departure date (to1) is not inclusive. So we modify it by 1 day.
      // But we do accept the same dates for arrival (from) and departure (to1).
      // In that case we leave the to date as is (equal to the from date).
      if ($to > $from) {
        $to
          ->modify('-1 day');
      }
      $this
        ->build_query($from, $to);
    }
  }
  protected function op_from_duration() {
    $this
      ->build_query(availability_calendar_parse_entry_date($this->value['from']), (int) $this->value['duration']);
  }

  /**
   * Helper method for the op_... methods that builds the query.
   *
   * @param DateTime $from
   * @param DateTime|integer $to_or_duration
   */
  protected function build_query($from, $to_or_duration) {
    availability_calendar_query_available($this->query, $this->table_alias, $this->real_field, $from, $to_or_duration, $this->definition['default_state']);
  }
  public function admin_summary() {
    $output = '';
    if (!empty($this->options['exposed'])) {
      $output = t('exposed');
    }
    else {
      $operators = $this
        ->operators();
      if (isset($operators[$this->operator]['summary'])) {
        $arguments = array();
        foreach ($this->value as $key => $value) {
          $arguments["@{$key}"] = $value;
        }
        $output = format_string($operators[$this->operator]['summary'], $arguments);
      }
    }
    return $output;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
availability_calendar_handler_filter_availability::$instance public static property
availability_calendar_handler_filter_availability::accept_exposed_input public function Check to see if input from the exposed filters should change the behavior of this filter. Overrides views_handler_filter::accept_exposed_input
availability_calendar_handler_filter_availability::admin_summary public function Display the filter on the administrative summary. Overrides views_handler_filter::admin_summary
availability_calendar_handler_filter_availability::build_query protected function Helper method for the op_... methods that builds the query.
availability_calendar_handler_filter_availability::change_element_into_date_popup protected function Changes a (text) form element into a date popup element.
availability_calendar_handler_filter_availability::couple_date_popups protected function Adds the necessary js to couple date popups to select a date range.
availability_calendar_handler_filter_availability::exposed_validate public function Validates our part of the exposed form. Overrides views_handler::exposed_validate
availability_calendar_handler_filter_availability::operators public function
availability_calendar_handler_filter_availability::operators_by_value public function
availability_calendar_handler_filter_availability::operator_options public function Provides a list of all the availability operators, optionally restricted to only the given property of the operators. Overrides views_handler_filter::operator_options
availability_calendar_handler_filter_availability::option_definition public function Information about options for all kinds of purposes will be held here. Overrides views_handler_filter::option_definition
availability_calendar_handler_filter_availability::op_at protected function
availability_calendar_handler_filter_availability::op_from_duration protected function
availability_calendar_handler_filter_availability::op_from_to protected function
availability_calendar_handler_filter_availability::op_from_to1 protected function
availability_calendar_handler_filter_availability::query public function Add this filter to the query. Overrides views_handler_filter::query
availability_calendar_handler_filter_availability::validate_valid_duration protected function
availability_calendar_handler_filter_availability::validate_valid_time_1 protected function
availability_calendar_handler_filter_availability::validate_value public function Validate that the values convert to something usable.
availability_calendar_handler_filter_availability::value_form public function Add validation and date popup(s) to the value form. Overrides views_handler_filter::value_form
availability_calendar_handler_filter_availability::__construct public function
views_handler::$handler_type public property The type of the handler, for example filter/footer/field.
views_handler::$query public property Where the $query object will reside:. 1
views_handler::$real_field public property The actual field in the database table, maybe different on other kind of query plugins/special handlers.
views_handler::$relationship public property The relationship used for this field.
views_handler::$table_alias public property The alias of the table of this handler which is used in the query.
views_handler::$view public property The top object of a view. Overrides views_object::$view
views_handler::access public function Check whether current user has access to this handler. 10
views_handler::broken public function Determine if the handler is considered 'broken'. 6
views_handler::case_transform public function Transform a string by a certain method.
views_handler::ensure_my_table public function Ensure the main table for this handler is in the query. This is used a lot. 8
views_handler::exposed_submit public function Submit the exposed handler form.
views_handler::expose_submit public function Perform any necessary changes to the form exposes prior to storage. There is no need for this function to actually store the data.
views_handler::extra_options public function Provide defaults for the handler.
views_handler::extra_options_form public function Provide a form for setting options. 1
views_handler::extra_options_submit public function Perform any necessary changes to the form values prior to storage. There is no need for this function to actually store the data.
views_handler::extra_options_validate public function Validate the options form.
views_handler::get_field public function Shortcut to get a handler's raw field value.
views_handler::get_join public function Get the join object that should be used for this handler.
views_handler::groupby_form public function Provide a form for aggregation settings. 1
views_handler::groupby_form_submit public function Perform any necessary changes to the form values prior to storage. There is no need for this function to actually store the data. 1
views_handler::has_extra_options public function If a handler has 'extra options' it will get a little settings widget and another form called extra_options. 1
views_handler::is_exposed public function Determine if this item is 'exposed', meaning it provides form elements to let users modify the view.
views_handler::needs_style_plugin public function Determine if the argument needs a style plugin. 1
views_handler::placeholder public function Provides a unique placeholders for handlers.
views_handler::post_execute public function Run after the view is executed, before the result is cached. 1
views_handler::pre_query public function Run before the view is built. 1
views_handler::sanitize_value public function Sanitize the value for output.
views_handler::set_relationship public function Called just prior to query(), this lets a handler set up any relationship it needs.
views_handler::show_expose_form public function Shortcut to display the exposed options form.
views_handler::ui_name public function Return a string representing this handler's name in the UI. 9
views_handler::use_group_by public function Provides the handler some groupby. 2
views_handler::validate public function Validates the handler against the complete View. 1
views_handler_filter::$always_multiple public property Disable the possibility to force a single value. 6
views_handler_filter::$always_required public property Disable the possibility to allow a exposed input to be optional.
views_handler_filter::$group_info public property Contains the information of the selected item in a gruped filter.
views_handler_filter::$no_operator public property Disable the possibility to use operators. 2
views_handler_filter::$operator public property Contains the operator which is used on the query.
views_handler_filter::$value public property Contains the actual value of the field.
views_handler_filter::build_group_form public function Build the form to let users create the group of exposed filters.
views_handler_filter::build_group_options public function Provide default options for exposed filters.
views_handler_filter::build_group_submit public function Save new group items, re-enumerates and remove groups marked to delete.
views_handler_filter::build_group_validate public function Validate the build group options form. 1
views_handler_filter::can_build_group public function Determine if a filter can be converted into a group.
views_handler_filter::can_expose public function Determine if a filter can be exposed. Overrides views_handler::can_expose 5
views_handler_filter::can_group public function Can this filter be used in OR groups? 1
views_handler_filter::convert_exposed_input public function Transform the input from a grouped filter into a standard filter.
views_handler_filter::exposed_form public function Render our chunk of the exposed filter form when selecting. Overrides views_handler::exposed_form
views_handler_filter::exposed_info public function Tell the renderer about our exposed form. Overrides views_handler::exposed_info
views_handler_filter::exposed_translate public function Make some translations to a form item to make it more suitable to exposing.
views_handler_filter::expose_form public function Options form subform for exposed filter options. Overrides views_handler::expose_form 2
views_handler_filter::expose_options public function Provide default options for exposed filters. Overrides views_handler::expose_options 2
views_handler_filter::expose_validate public function Validate the options form. Overrides views_handler::expose_validate
views_handler_filter::group_form public function Build a form with a group of operator | values to apply as a single filter.
views_handler_filter::group_multiple_exposed_input public function Options available for a grouped filter which uses checkboxes.
views_handler_filter::init public function Provide some extra help to get the operator/value easier to use. Overrides views_handler::init 2
views_handler_filter::is_a_group public function Returns TRUE if the exposed filter works like a grouped filter. Overrides views_handler::is_a_group
views_handler_filter::multiple_exposed_input public function Indicate whether users can select multiple group items. Overrides views_handler::multiple_exposed_input
views_handler_filter::operator_form public function Options form subform for setting the operator. 6
views_handler_filter::operator_submit public function Perform any necessary changes to the form values prior to storage.
views_handler_filter::operator_validate public function Validate the operator form.
views_handler_filter::options_form public function Provide the basic form which calls through to subforms. Overrides views_handler::options_form 4
views_handler_filter::options_submit public function Simple submit handler. Overrides views_handler::options_submit
views_handler_filter::options_validate public function Simple validate handler. Overrides views_handler::options_validate 1
views_handler_filter::prepare_filter_select_options public function Sanitizes the HTML select element's options.
views_handler_filter::show_build_group_button public function Shortcut to display the build_group/hide button.
views_handler_filter::show_build_group_form public function Shortcut to display the exposed options form.
views_handler_filter::show_expose_button public function Shortcut to display the expose/hide button. Overrides views_handler::show_expose_button
views_handler_filter::show_operator_form public function Shortcut to display the operator form.
views_handler_filter::show_value_form public function Shortcut to display the value form.
views_handler_filter::store_exposed_input public function Store the exposed input for processing later. Overrides views_handler::store_exposed_input
views_handler_filter::store_group_input public function If set to remember exposed input in the session, store it there.
views_handler_filter::value_submit public function Perform any necessary changes to the form values prior to storage. 1
views_handler_filter::value_validate public function Validate the options form. 3
views_object::$definition public property Handler's definition.
views_object::$options public property Except for displays, options for the object will be held here. 1
views_object::altered_option_definition function Collect this handler's option definition and alter them, ready for use.
views_object::construct public function Views handlers use a special construct function. 4
views_object::destroy public function Destructor. 2
views_object::export_option public function 1
views_object::export_options public function
views_object::export_option_always public function Always exports the option, regardless of the default value.
views_object::options Deprecated public function Set default options on this object. 1
views_object::set_default_options public function Set default options.
views_object::set_definition public function Let the handler know what its full definition is.
views_object::unpack_options public function Unpack options over our existing defaults, drilling down into arrays so that defaults don't get totally blown away.
views_object::unpack_translatable public function Unpack a single option definition.
views_object::unpack_translatables public function Unpacks each handler to store translatable texts.
views_object::_set_option_defaults public function