Cms: Chaining multiple relatedTo methods in element query

Created on 28 Feb 2020  Â·  13Comments  Â·  Source: craftcms/cms

It would be pretty useful if we could chain multiple relatedTo methods in element query. Of course then it is matter if we want to use and or or parameter - so i guess there could be also separate method for setting it up, like:

{{craft.entries.setRelated('and').relatedTo(element1).relatedTo(element2)}}`
enhancement site development

Most helpful comment

@brandonkelly is the below linking the solution you are recommending for this? So would allow for multiple OR statements to be joined with AND.

{% set query = craft.entries()
    .relatedTo([
        'and',
        [
            'or',
            element1,
            element2
        ],
        [
            'or',
            element3,
            element4
        ],
    ]) %}

I actually thought that would work, but turns out you would have needed to specify the relation types, like this:

{% set query = craft.entries()
    .relatedTo([
        'and',
        {targetElement: ['or', element1, element2]},
        {targetElement: ['or', element3, element4]},
    ]) %}

That said, I’ve just made your original syntax possible for the next release, as well as added a new andRelatedTo param which could simplify it a bit:

{% set query = craft.entries().relatedTo([element1, element2]) %}

{# ... #}

{% do query.andRelatedTo([element3, element4]) %}

All 13 comments

No other params work like that, but I could see us doing something similar to where / andWhere: Any time you call where(), it will override the existing query conditions. But if you call andWhere() it will add a new and condition to the query.

In the meantime, you can pull off what you’re trying to do by doing:

{% set query = craft.entries()
    .relatedTo([
        'and',
        element1,
        element2
    ]) %}

@brandonkelly

No other params work like that, but I could see us doing something similar to where / andWhere: Any time you call where(), it will override the existing query conditions

Nice solution!

In the meantime, you can pull off what you’re trying to do by doing:

I was already doing that, but it meant that i first had to create array with relatedTo params, then append multiple elements to this array and finally use it in element query.

I would like to have the ability to have multiple relatedTo()'s as well. Only having one relatedTo() limits the possibility of having multiple conditions.

Example in pseudocode of what I would like to achieve without writing custom PHP: (foo OR bar) AND (brandon OR brad) AND (cat OR dog)

Right now I am solving this with a little custom Twig extension doing almost exactly what \craft\elements\db\ElementQuery::_applyRelatedToParam does:

public static function appendRelatedTo(ElementQuery $query, array $relatedTo): bool
{
    $parser = new ElementRelationParamParser([
        'fields' => $query->customFields ? ArrayHelper::index($query->customFields, 'handle') : []
    ]);

    $condition = $parser->parse($relatedTo);
    if ($condition === false) {
        return false;
    }

    $query->andWhere($condition);
    return true;
}

Cheers!

Is this something that might be added in the future? For complex sites this is a pretty basic requirement e.g. product filters.

@Wiejeben how is your workaround used? I need to do something similar but in PHP :/

It’s already possible via the current relatedTo param – see https://github.com/craftcms/cms/issues/5733#issuecomment-592601183.

Hey @brandonkelly this is they type of query I'm trying to perform

Screen Shot 2021-03-17 at 10 00 14 AM

Each column e.g. "Type" would be an OR but then it would be an "AND" between each column.

In this example it should show all Shutters that have floral or stripe styles.

Is that possible?

Yes, it’s possible.

Do you have an example of how that might work? 😅

Got it!

I used ElementRelationParamParser to prepare the related to queries and then parse them into my where statements.

Example:

use craft\elements\db\ElementRelationParamParser;
$results->find()->sections('mySection');
$parser = new ElementRelationParamParser();
$relatedTo = $parser->parse($relatedElements); // defaults to OR
$results->andWhere($relatedTo); // can then chain multiple andWhere statements

@brandonkelly is the below linking the solution you are recommending for this? So would allow for multiple OR statements to be joined with AND.

{% set query = craft.entries()
    .relatedTo([
        'and',
        [
            'or',
            element1,
            element2
        ],
        [
            'or',
            element3,
            element4
        ],
    ]) %}

I actually thought that would work, but turns out you would have needed to specify the relation types, like this:

{% set query = craft.entries()
    .relatedTo([
        'and',
        {targetElement: ['or', element1, element2]},
        {targetElement: ['or', element3, element4]},
    ]) %}

That said, I’ve just made your original syntax possible for the next release, as well as added a new andRelatedTo param which could simplify it a bit:

{% set query = craft.entries().relatedTo([element1, element2]) %}

{# ... #}

{% do query.andRelatedTo([element3, element4]) %}

You're a legend. Thank you.

Craft 3.6.11 is out now with the relatedTo change and the new andRelatedTo param ✨

Was this page helpful?
0 / 5 - 0 ratings

Related issues

michel-o picture michel-o  Â·  3Comments

RitterKnightCreative picture RitterKnightCreative  Â·  3Comments

rynpsc picture rynpsc  Â·  3Comments

angrybrad picture angrybrad  Â·  3Comments

darylknight picture darylknight  Â·  3Comments