I am not experienced developer, so I assume this should be easy for those who are.

I've been using http://views.doc.logrus.com/ as a reference for views filter handler development, but I can't find a handler life-cycle, and unable to determine when the data in view filters becomes available for use in other filter handlers. Here is a case study, that elaborates desired goal.

Case Study Example

Filters:
A - Node: Type
B - Taxonomy: Term ID
C - "New Node Module": Title

Exposed filter C provides a list of "new node module" nodes that are through various tables related to nodes that have to be filtered prior being displayed in the view. Exposed filters A and B should provide lists of options that are to be used to filter-out the filter C, thus limiting the number of items available in it and making it less cluttered.

So far I've managed to display existing filters (A & B, in the case above) to serve as filtering components of the filter C, during add filter procedure. Here is the filter handler code (Note that "New Node Module" and "new_module" references are used only for presentation purposes, not a for a real module name!):

class new_module_views_handler_filter_new_module_title extends views_handler_filter_many_to_one {
  
  function has_extra_options() { return TRUE; }

  function get_value_options() { /* don't overwrite the value options */ }

  function option_definition() {
    $options = parent::option_definition();

    $options['filters'] = array();

    return $options;
  }

  function extra_options_form(&$form, &$form_state) {

    $filters = array();
    foreach ($this->view->get_items('filter') as $filter) {
      if ($filter->table != 'new_module' ) {
        $filters[$filter['id']] = $filter['id'];
      }
    }

    $form['markup_start'] = array(
      '#value' => '<div class="views-left-40">',
    );

    $form['filters'] = array(
      '#type' => 'checkboxes',
      '#title' => t('View filters'),
      '#options' => $filters,
      //'#default_value' => $this->options['filters'],
    );

    $form['markup_end'] = array(
      '#value' => '</div>',
    );
  }
  
  function value_form(&$form, &$form_state) {
    
    foreach (array_filter($this->options['filters']) as $filter_id) {
      $filter = $this->view->get_item($this->view->current_display, 'filter', $filter_id);
      
    }
    
    $form['title'] = array(
      '#type' => 'select',
      '#title' => t('Title'),
      '#multiple' => FALSE,
      '#options' => $filter['value'],
      '#size' => min(9, count($filter['value'])),
      //'#default_value' => $default_value,
    );
  }
}

Comments

miraclestyle’s picture

What I really need is the function name to extend from derived (views_handler_filter_many_to_one) handler. This function should presumably execute at the stage where the filters' lists have been populated. Or, perhaps there is a views method to call to get that data?

merlinofchaos’s picture

Status: Active » Fixed

First, what you're doing is not actually very easy, so don't get down about that part.

The problem is that I think you want what is *available* in filter C to test on what is chosen in filters A and B, which means checking the results of the form processing before the form is even processed. In general, FAPI doesn't like to do that.

The easiest thing to do may be to just examine $_GET and see what data the user has selected when generating the options available in filter C. It's not technically right, but Views Exposed Filter forms are REST-style forms, so it's probably ok in this instance. Do keep in mind that malicious users could put arbitrary data into this location, so validate everything if it might make a difference. As long as you follow that rule (validate validate validate) then there's nothing actually wrong about it.

miraclestyle’s picture

Many thanks for the response!

As the matter or fact, what I need is a set of arguments that originate from filters A & B that will be used to build a db query to populate filter C.

And I was actually thinking of using $_GET to obtain arguments for filter C, but suspected that it wouldn't be in compliance with the Views.

That's why I've decided to post here, and hoped that there is a solution (A & B selected values available before forms building) already implemented in Views architecture.

Thank you again.

miraclestyle’s picture

Status: Fixed » Active

I am reopening this thread to avoid making new post with the same relevance.

If we reconsider the above case study with one of the argument filters (A or B) hidden with fixed value (configured during view creation), could the following code be useful?

Please note the URL validation isn't in place yet. My only concerns right now are "consistent" places where to look for the filters' argument values!


 function value_form(&$form, &$form_state) {
    
    foreach (array_filter($this->options['type_filters']) as $filter_id) {
      $filter = $this->view->get_item($this->view->current_display, 'filter', $filter_id);
      if ($filter['exposed']) {
        // TODO: Argument validation!
        $this->options['filters_input']['type_filters'] = is_array($_GET[$filter_id]) ? $_GET[$filter_id] : array($_GET[$filter_id]);
      }
      else {
        $this->options['filters_input']['type_filters'] = is_array($filter['value']) ? $filter['value'] : array($filter['value']);
      }
    }
    
    foreach (array_filter($this->options['taxonomy_filters']) as $filter_id) {
      $filter = $this->view->get_item($this->view->current_display, 'filter', $filter_id);
      if ($filter['exposed']) {
        // TODO: Argument validation!
        $this->options['filters_input']['taxonomy_filters'] = is_array($_GET[$filter_id]) ? $_GET[$filter_id] : array($_GET[$filter_id]);
      }
      else {
        $this->options['filters_input']['taxonomy_filters'] = is_array($filter['value']) ? $filter['value'] : array($filter['value']);
      }
    }
   
    $filter_values = array_merge(array_filter($this->options['filters_input']['type_filters']), array_filter($this->options['filters_input']['taxonomy_filters']));
...

Elvin.

miraclestyle’s picture

Also, note that

"$this->options['filters_input']['taxonomy_filters'] = is_array($_GET[$filter_id]) ? $_GET[$filter_id] : array($_GET[$filter_id])"

and

"$this->options['filters_input']['type_filters'] = is_array($_GET[$filter_id]) ? $_GET[$filter_id] : array($_GET[$filter_id])"

will be rewritten to support multiple filters in addition to URL validation!

Elvin.

miraclestyle’s picture

Status: Active » Fixed

I am fixing this thread as I believe that I've found a storage of input values from the filters. Thus I don't use $_GET to extract the arguments. I haven't checked if the view's stored values are validated prior being imported in view structure though.

For exposed filters value is stored in:

"$this->view->exposed_input[filter_id]",

and for hidden ones, I used the following lines of code:

...

 function value_form(&$form, &$form_state) {

...

// Get a current display of the view.
$display_id = ($this->view->display_handler->is_defaulted('filters')) ? 'default' : $this->view->current_display;

// Get a view item from which you need a value.
$filter = $this->view->get_item($display_id, 'filter', $filter_id);

// Have the value for whatever purpose you need it.
$value = $filter['value'];
...

}

If anyone objects to this approach, please do comment of what's wrong with this and propose a better solution.

Thanks.

Elvin.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.