statamic / ideas

💡Discussions on ideas and feature requests for Statamic
https://statamic.dev
32 stars 1 forks source link

Support an 'intersect' query #434

Open afonic opened 3 years ago

afonic commented 3 years ago

Bug Description

Using the :in condition doesn't work when a field can have more than one option.

This is true using the collection tag like: {{ collection:cars equipment:in="aircondition" }}

or even in the Content API.

Using the same condition in a single select field works as indented.

How to Reproduce

I have created a sample repo with code that reproduces this problem: https://github.com/afonic/multiselect

Environment

Statamic version: 3.0.37

PHP version: 7.4.11

Install method (choose one):

afonic commented 3 years ago

After further investigation, in the Stache/Query/Builder abstract class, the filterWhereIn method:

protected function filterWhereIn($values, $where)
{
    return $values->filter(function ($value) use ($where) {
        return in_array($value, $where['values']);
    });
}

will not return true if $value is an Array, and it seems that for multiple fields it is.

One could argue that you can use another condition, like :contains, but that cannot accept piped arguments.

I could provide a PR but I'm not sure what the right way to fix this would be.

Edit:

Something like this works:

protected function filterWhereIn($values, $where)
{
    return $values->filter(function ($value) use ($where) {
        if (is_array($value)) {
            foreach ($value as $term) {
                if (in_array($term, $where['values'])) {
                    return true;
                }
            }
        }
        return in_array($value, $where['values']);
    });
}

Of course it could be cleaner? And the filterWhereNotIn method could need changes as well.

edalzell commented 3 years ago

fyi @afonic you're looking for the array intersection function, might make that code a bit nicer.

afonic commented 3 years ago

@edalzell I'not really familiar with Laravel, so I think I'll just report the bug and leave it to the experts!

jasonvarga commented 3 years ago

in is working as intended, but the intersect functionality would be a new thing.

I went into more detail on your PR (thank you again) https://github.com/statamic/cms/pull/3103#issuecomment-759779772

I'll move this to the ideas repo.

afonic commented 3 years ago

@jasonvarga I think moving this to ideas is partly only correct.

The :in condition does not work in objects saved as arrays as stated here: https://statamic.dev/conditions#arrayobject-conditions (or I am doing something really wrong).

jasonvarga commented 3 years ago

Incorrectly documented. The description of in earlier on the page is more accurate.

afonic commented 3 years ago

Thank you.

Also please note that if you use the :in condition in a field that gets saved as an array (multiple taxonomies, multiple select, checkboxes) it returns no item. That's why I (incorrectly) thought to "fix" the filterWhereNotIn method.

I'll be using Vue to "fix" this for now in my project, because it seems unsolvable, especially using the Content API, but I might come back to it if you are open for a PR for "intersect" filter.