Categories


Archives


Recent Posts


Categories


Magento 2: How to Apply FilterGroups and Filters

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

I touched on this in my longer Magento 2: Understanding Object Repositories tutorial, but it’s worth repeating. The relationship between individual filters and filter groups in Magento 2 repositories is inconsistent. There’s some tribal wisdom floating around that filters should be applied as OR conditions, and filter groups combined as AND conditions.

This tribal wisdom holds true in the product repository

#File: vendor/magento/module-catalog/Model/ProductRepository.php
protected function addFilterGroupToCollection(
    MagentoFrameworkApiSearchFilterGroup $filterGroup,
    Collection $collection
) {
    $fields = [];
    $categoryFilter = [];
    foreach ($filterGroup->getFilters() as $filter) {
        $conditionType = $filter->getConditionType() ? $filter->getConditionType() : 'eq';

        if ($filter->getField() == 'category_id') {
            $categoryFilter[$conditionType][] = $filter->getValue();
            continue;
        }
        $fields[] = ['attribute' => $filter->getField(), $conditionType => $filter->getValue()];
    }

    if ($categoryFilter) {
        $collection->addCategoriesFilter($categoryFilter);
    }

    if ($fields) {
        $collection->addFieldToFilter($fields);
    }

}

Where, for each group, Magento builds an array of filter arrays, and then adds them to addFieldToFiler.

However, it does not apply to a CMS page repository.

#File: vendor/magento/module-cms/Model/PageRepository.php
foreach ($criteria->getFilterGroups() as $filterGroup) {
    foreach ($filterGroup->getFilters() as $filter) {
        if ($filter->getField() === 'store_id') {
            $collection->addStoreFilter($filter->getValue(), false);
            continue;
        }
        $condition = $filter->getConditionType() ?: 'eq';
        $collection->addFieldToFilter($filter->getField(), [$condition => $filter->getValue()]);
    }
}

Where Magento applies addFieldToFilter individually for each filter, which results in individual filters applied as an AND. If you think this is due to an EAV vs. Simple CRUD limitation – think again. If we look at the coupon repository, we see filters applied similarly to the product repository

#File: vendor/magento/module-sales-rule/Model/CouponRepository.php

protected function addFilterGroupToCollection(
    MagentoFrameworkApiSearchFilterGroup $filterGroup,
    Collection $collection
) {
    $fields = [];
    $conditions = [];
    foreach ($filterGroup->getFilters() as $filter) {
        $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq';
        $fields[] = $filter->getField();
        $conditions[] = [$condition => $filter->getValue()];
    }
    if ($fields) {
        $collection->addFieldToFilter($fields, $conditions);
    }
}

For each group, an array of filter arrays is built up, and passed to addFieldToFilter.

For what it’s worth, and to answer the question posed by our title, the method in the CouponRepository feels like the right approach here for generic CRUD model repositories.

Copyright © Alan Storm 1975 – 2019 All Rights Reserved

Originally Posted: 24th April 2016