This is a 2 part issue related to this use case:

problem: Joe user wants to compose a view that shows all content of type salad that has any one of 3 ingredients (stored as taxonomy terms). That view needs to also filter the salads dynamically via the url to only show for a specific ingredient.

solution: a view is composed with a taxonomy->tid filter that limits to only the 3 desired ingredients/terms. the taxonomy->tid argument is then applied with "if no argument is supplied, show all values" and validation is set to the same "ingredients" vocabulary.

part one of this issue when you compose a view that has both a filter and an argument for taxonomy->tid, the many_to_one argument handler takes the values that are specifically specified in the filter, and negates them out in the join. the desired output based on this functionality should be a join that looks something like:

....
LEFT JOIN term_node term_node2 ON node.vid = term_node2.vid AND (term_node2.tid != 3 AND term_node2.tid != 2 AND term_node2.tid != 6)
...

but in actuality you get only the last selected term from the filter value:

....
LEFT JOIN term_node term_node2 ON node.vid = term_node2.vid AND term_node2.tid != 6
...

this is due to a foreach() in handlers.inc that loops through all the values passed in the many_to_one queue, but only sets the current index to $join->extra in this code:

// views/includes/handlers.inc line 683
...
        foreach ($this->handler->value as $value) {
          $join = $this->get_join();
          if ($this->handler->operator == 'and') {
            $join->type = 'INNER';
          }
          $join->extra = array(
            array(
              'field' => $this->handler->real_field,
              'value' => $value,
              'numeric' => !empty($this->handler->definition['numeric']),
            ),
          );
...

a patch that addresses this part of the issue is attached, but probably needs lots of refinement and testing.

part 2 of this issue is that if this is implemented, you wind up with a query that looks like so:

SELECT node.nid AS nid,
   node.title AS node_title,
   node.changed AS node_changed
 FROM node node 
 INNER JOIN term_node term_node ON node.vid = term_node.vid
 LEFT JOIN term_node term_node2 ON node.vid = term_node2.vid AND (term_node2.tid != 3 AND term_node2.tid != 2 AND term_node2.tid != 6)
 WHERE (node.type in ('salad')) AND (term_node.tid IN (3, 2, 6)) AND (term_node2.tid = 3)

Note that term_node2 is filtering out tid's 2,3 & 6, then specifically looking for tid 3 in the where clause. This is because the argument is excluding the values from the filter even though they are allowed values it can filter by.

I'd suggest a few possible approaches here.
1) it might make sense for the multiple to one functionality to distinguish between filters and arguments to keep them separate from each other.
2) make term_node not participate in the multiple to one functionality.
3) allow users to chose an opt in / opt out of the multiple to one functionality

I'm happy to put together a patch for this, but I'd rather go the approach people want rather than what I want :)

Comments

netw3rker’s picture

Version: 6.x-2.9 » 6.x-2.11

switched this to the proper version.. selected 2.9 before whoops ;)

netw3rker’s picture

Status: Active » Needs review
dawehner’s picture

StatusFileSize
new1.02 KB

I'm not convinced totally.

Don't you want to avoid to override $join->extra?

So what about this patch?

ludo.r’s picture

I have a similar issue.

My view takes a termID as an argument from URL.This argument is always present.
I added a taxonomy term filter to include the termIDs that can be displayed (Is one of).

But it seems the request always exclude the last termID from the results :

SELECT node.nid AS nid,
   node_data_field_doc_date.field_doc_date_value AS node_data_field_doc_date_field_doc_date_value
 FROM node node 
 INNER JOIN term_node term_node ON node.vid = term_node.vid
 LEFT JOIN term_node term_node2 ON node.vid = term_node2.vid ****** AND term_node2.tid != 83 ********
 LEFT JOIN content_type_document node_data_field_doc_date ON node.vid = node_data_field_doc_date.vid
 WHERE (node.status <> 0) AND (node.type in ('document')) AND (term_node.tid IN (79, 81, 82, 83)) AND (term_node2.tid = 83)
   ORDER BY node_data_field_doc_date_field_doc_date_value DESC

Do you see this? AND term_node2.tid != 83
So when i want to show the termID 83 the request returns no result.
When using termID 79,81 or 82 it works.


If i uncheck the termID from the filter, then it is the termID 83 that is excluded :

SELECT node.nid AS nid,
   node_data_field_doc_date.field_doc_date_value AS node_data_field_doc_date_field_doc_date_value
 FROM node node 
 INNER JOIN term_node term_node ON node.vid = term_node.vid
 LEFT JOIN term_node term_node2 ON node.vid = term_node2.vid ****** AND term_node2.tid != 82 ******
 LEFT JOIN content_type_document node_data_field_doc_date ON node.vid = node_data_field_doc_date.vid
 WHERE (node.status <> 0) AND (node.type in ('document')) AND (term_node.tid IN (79, 81, 82)) AND (term_node2.tid = 82)
   ORDER BY node_data_field_doc_date_field_doc_date_value DESC

Am i missing something or is this a bug?

dawehner’s picture

Before committing that patch someone definitive has to test that.

tim.plunkett’s picture

Issue tags: +Needs tests

Fixing tag.

Status: Needs review » Needs work
Issue tags: -Needs tests

The last submitted patch, 982728-handler_extra.patch, failed testing.

mustanggb’s picture

Status: Needs work » Closed (won't fix)