As I understand it Views Filters provide a wide range of operators (=, !=, contains, etc.,) but require a fixed value when you create the view. Views Arguments, meanwhile, allow the NID/taxonomy term/whatever to passed along on the fly, but generally offer only an exact match (with a few options for taxonomy depth, A/B/C-style glossaries, etc.)

What I can't figure out how to do, however, is craft a view that will let me pass along an argument that will use more complex operators.

Coding by hand, I can do something like this:

$query = "SELECT DISTINCT n.nid, n.title  FROM {node} n
  INNER JOIN {content_type_whatever} ct ON n.nid = ct.nid 
  WHERE ct.field_some_textfield_value = '$var1' AND
  ct.field_some_integer_value BETWEEN $var2 AND $var3
  AND n.status = 1 AND n.nid != '$nid'
  ORDER BY n.title ASC";

... where $var1, $var2 and $var3 are user-provided or calculated on the fly.

That's all well and good -- and given that I know about as much PHP as your average chimp, I'm rather proud of myself for getting that far! But Views does such a great job of returning themeable results, allowing for easy insertion into other nodes, etc., that doing it all from scratch seems foolish (and painful!).

So my question is: Does Views allow for this sort of thing? Is there any way to use the equivalent of BETWEEN or IN with arguments? (Or alternatively, to pass values to a Views Filter on the fly?)

It *seems* as though argument handling code might make this possible. But I've scoured the documentation, snippets, etc., and can't find anything that gets me rolling in that direction -- or makes clear that I'm just out of luck.

So if anyone can help answer this for me, and I'd be VERY grateful. And I promise to write up and submit whatever I learn to the Views Documentation and/or FAQ over on Drupal Groups!

Thanks

Comments

TKS’s picture

Status: Active » Closed (fixed)

After much searching and experimenting, I finally figured out how to make this work. A comment posted by quicksketch in the Views Documentation was the clue I needed -- he'd crafted some argument handling code that uses arguments to set filters (in that case, for date ranges). It's seemingly a great solution -- the only downside I've found is that, unlike "normal" views arguments, you can't use a wildcard.

What I needed to was a dynamically generated view that would show other nodes that were similar to the one a user was looking at -- ie, where data in a given field was within +/- 10 percent. We're working with information on school districts (demographics, funding, test scores, etc.), so in the template for each node, there'd be a link that took you to the view showing other similar districts.

Initially I passed only the values from the appropriate fields, so that the hard-coded link in the template looked something like:
...a href="/viewname/<?php print $field_one[0]['view']; ?>/<?php print $field_two[0]['view']; ?>/etc...

Once certain that it worked, I went ahead and added a quickie form to the template, so that user can specify which fields they want to use in their comparison, and how similar they want each to be -- +/- 5 percent, +/- 20 percent, etc. The resulting URL has 11 arguments in it -- the 10 referenced below, and one "normal" argument ($args[0]) that is handled by Views in the usual way.

So here's my argument handling code as in now stands -- hope others find it useful.

// Generate the filter variables, using arguments 
// passed in to the view from the URL

$plus = ($args[1] / 100) + 1;
$minus = 1 - ($args[1] / 100);
$students_low = ($args[2] * $minus);
$students_high = ($args[2] * $plus);
$plus = ($args[3] / 100) + 1;
$minus = 1 - ($args[3] / 100);
$poverty_low = ($args[4] * $minus);
$poverty_high = ($args[4] * $plus);
$plus = ($args[5] / 100) + 1;
$minus = 1 - ($args[5] / 100);
$ppe_low = ($args[6] * $minus);
$ppe_high = ($args[6] * $plus);
$plus = ($args[7] / 100) + 1;
$minus = 1 - ($args[7] / 100);
$g4reading_low = ($args[8] * $minus);
$g4reading_high = ($args[8] * $plus);
$plus = ($args[9] / 100) + 1;
$minus = 1 - ($args[9] / 100);
$g4math_low = ($args[10] * $minus);
$g4math_high = ($args[10] * $plus);



// Add filter to establish low end of student body size
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_total_kids.field_total_kids_value_default',
    'value' => $students_low,
    'operator' => '>',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_total_kids.field_total_kids_value_default',
  );

// Add filter to establish high end of student body size
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_total_kids.field_total_kids_value_default',
    'value' => $students_high,
    'operator' => '<',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_total_kids.field_total_kids_value_default',
  );

// AFTER HERE THE CODE IS FAIRLY REDUNDANT, JUST DOING
// THE SAME BASIC ROUTINE FOR EACH OF FIELD AND ITS
// PLUS-MINUS x PERCENT RANGE
// BUT DON'T OVERLOOK THE IMPORTANT CACHE-CLEARING
// COMMAND AT THE VERY END


// Add filter to establish low end of poverty rate
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_percent_poverty.field_percent_poverty_value_default',
    'value' => $poverty_low,
    'operator' => '>',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_percent_poverty.field_percent_poverty_value_default',
  );

// Add filter to establish high end of poverty rate
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_percent_poverty.field_percent_poverty_value_default',
    'value' => $poverty_high,
    'operator' => '<',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_percent_poverty.field_percent_poverty_value_default',
  );

// Add filter to establish low end of per-pupil expenditures
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_per_pupil.field_per_pupil_value_default',
    'value' => $ppe_low,
    'operator' => '>',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_per_pupil.field_per_pupil_value_default',
  );

// Add filter to establish high end of per-pupil expenditures
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_per_pupil.field_per_pupil_value_default',
    'value' => $ppe_high,
    'operator' => '<',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_per_pupil.field_per_pupil_value_default',
  );

// Add filter to establish low end of G4 reading proficiency
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_nclb_d4_reading_0405.field_nclb_d4_reading_0405_value_default',
    'value' => $g4reading_low,
    'operator' => '>',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_nclb_d4_reading_0405.field_nclb_d4_reading_0405_value_default',
  );

// Add filter to establish high end of G4 reading proficiency
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_nclb_d4_reading_0405.field_nclb_d4_reading_0405_value_default',
    'value' => $g4reading_high,
    'operator' => '<',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_nclb_d4_reading_0405.field_nclb_d4_reading_0405_value_default',
  );

// Add filter to establish low end of G4 math proficiency
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_nclb_d4_math_0405.field_nclb_d4_math_0405_value_default',
    'value' => $g4math_low,
    'operator' => '>',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_nclb_d4_math_0405.field_nclb_d4_math_0405_value_default',
  );

// Add filter to establish high end of G4 reading proficiency
  $view->filter[] = array(
    'vid' => $view->vid,
    'tablename' => '',
    'field' => 'node_data_field_nclb_d4_math_0405.field_nclb_d4_math_0405_value_default',
    'value' => $g4math_high,
    'operator' => '<',
    'options' => '',
    'position' => count($view->filter),
    'id' => 'node_data_field_nclb_d4_math_0405.field_nclb_d4_math_0405_value_default',
  );

// IMPORTANT: Invalidate the cached query for this view, as it'll need to be regenerated on each request
$view->is_cacheable = 0;

Simple, huh?... In any case, changing this thread's status to "closed."

dharamgollapudi’s picture

Subscribing....

mssarath’s picture

subscribing

asak’s picture

very nice code (and very very useful too!) ;)

Should this work with drupal 5.10 ? newest views?

Thank you!

maria_zk’s picture

subscribing

joachim’s picture

subscribing

aac’s picture

Subscribing!!

joachim’s picture

Category: support » feature
Status: Closed (fixed) » Active

In Views 2, a handler can do pretty much anything to the query.
So a special argument handler could take an argument like "1-5" and turn that into a "WHERE foo BETWEEN 1 AND 5" in the query -- see how the calendar module's argument works for a similar technique.
Furthermore, arguments can work together, like the taxonomy depth modifier.
So you could have a path like myview/1/5 where the two argument 1 and 5 combine to make the between. Would require a bit more work for the two handlers to be aware of each other, but still doable.

The other question is for which arguments and which handlers does this make sense -- how high in the class tree ought this functionality to go?

gravisrs’s picture

+1 subscribing.

Would be very nice to have (in additional to exact matches) each argument (at least from cck & date) that is a type of

1. integer, date (all sub-types) - to have configurable options of : >, >=, <, <=

2. string (varchars) - to have configurable options of LIKE: %xxx%, %xxx, xxx%

These simple options would cover all mentioned "BETWEEN" cases but also exclusive ranges like [x<10 || x>20] (using views OR).

MrPeanut’s picture

Subscribing.

xjm’s picture

xjm’s picture

See also: #376932: String Argument Handlers for the string comparison case as described in #9. Worth testing.

iamjon’s picture

Status: Active » Closed (duplicate)

From what I understand using a arguments to alter filters is a feature request that is being handled here:
#357082: Pull filter value from an argument? for 3x only, and unfortunately will not be available for views 2.x. Please follow tks's instructions or follow the progress of the 3x feature request from there.

Otherwise you can also filter a view with another view #720422: Write tutorial explaining how to exclude nodes from view by another view? I'm working on the tutorial there.

If you have a workaround that can be placed in a tutorial please post it and I will write up a patch.

Marking this as a duplicate of #357082: Pull filter value from an argument?