14

I'm trying to use a product repository to fetch a list of products. I want to fetch based on two filters, combined with an AND criteria, but things don't seem to be working. Do I not understand how filter groups work? Or is this a bug that should be reported?

Specifically, (silly example for simplicity's sake) I have a constructor where I inject a filter builder, filter group builder, and a search criteria builder

public function __construct(
    \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
    \Magento\Framework\Api\FilterBuilder $filterBuilder,
    \Magento\Framework\Api\Search\FilterGroupBuilder $filterGroupBuilder 
)
{
    $this->searchCriteriaBuilder = $searchCriteriaBuilder;
    $this->filterBuilder         = $filterBuilder;
    $this->filterGroupBuilder    = $filterGroupBuilder;
}

Then, later on in a method, I use the filter builders to build two filters

    $filter1 = $this->filterBuilder->setField('sku')
            ->setValue('24-MB01')
            ->setConditionType('eq')
            ->create();

    $filter2 = $this->filterBuilder->setField('sku')
            ->setValue('WT08-XS-Black')
            ->setConditionType('eq')
            ->create();

Then I use the filter group builder to build a filter group that consists of these two filters

    $filter_group = $this->filterGroupBuilder
        ->addFilter($filter1)
        ->addFilter($filter2)
        ->create();

Then I used a search criteria builder, set the filter group on it

    $criteria = $this->searchCriteriaBuilder
        ->setFilterGroups([$filter_group])
        ->setPageSize(100)
        ->create();            
    return $criteria

Finally, when I use this criteria with a product repository (used elsewhere, leaving out constructor and di to avoid confusion)

/* @var Magento\Catalog\Api\ProductRepositoryInterface */
$list = $productRepository->getList($searchCriteria);  

The call is succesfull but I get back two products. i.e. the SKU filter was applied as a OR, not an AND. I'd expect this query to return nothing.

If I dig into the Magento\Catalog\Api\ProductRepository class, and take a look at the collection's select statment

protected function addFilterGroupToCollection(
    \Magento\Framework\Api\Search\FilterGroup $filterGroup,
    Collection $collection
) {
    //...
    if ($fields) {
        $collection->addFieldToFilter($fields);
    }

    //printf lives in my heart forever
    echo($collection->getSelect()->__toString());
    exit;
}               

I see the criteria added with an OR

SELECT `e`.*, IF(at_status.value_id > 0, at_status.value, at_status_default.value) AS `status`, IF(at_visibility.value_id > 0, at_visibility.value, at_visibility_default.value) AS `visibility` 

FROM `catalog_product_entity` AS `e` 

INNER JOIN `catalog_product_entity_int` AS `at_status_default` ON (`at_status_default`.`entity_id` = `e`.`entity_id`) AND (`at_status_default`.`attribute_id` = '94') AND `at_status_default`.`store_id` = 0 LEFT JOIN `catalog_product_entity_int` AS `at_status` ON (`at_status`.`entity_id` = `e`.`entity_id`) AND (`at_status`.`attribute_id` = '94') AND (`at_status`.`store_id` = 1) 

INNER JOIN `catalog_product_entity_int` AS `at_visibility_default` ON (`at_visibility_default`.`entity_id` = `e`.`entity_id`) AND (`at_visibility_default`.`attribute_id` = '96') AND `at_visibility_default`.`store_id` = 0 LEFT JOIN `catalog_product_entity_int` AS `at_visibility` ON (`at_visibility`.`entity_id` = `e`.`entity_id`) AND (`at_visibility`.`attribute_id` = '96') AND (`at_visibility`.`store_id` = 1)

WHERE ((`e`.`sku` = '24-MB01') OR (`e`.`sku` = 'WT08-XS-Black')) 

Is this a bug? Is there a way (short of relying directly on the product collections and ditching the repositories) to make this work?

2

2 Answers 2

19

Actual annotation of \Magento\Framework\Api\Search\FilterGroup says (class phpDoc):

Groups two or more filters together using a logical OR

It means that you need to create two groups with one filter in each.

2
2

In Magento 2 all the filters in same FilterGroup will be added using OR operator. But all the FilterGroup will be added using AND operator. So you will need to add multiple FilterGroups as below:

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$searchCriteria = $objectManager->create('\Magento\Framework\Api\SearchCriteria');
$filter = $objectManager->create('\Magento\Framework\Api\Filter');
$filter->setField('category_id');
$filter->setValue(array(1, 2, 3));
$filter->setConditionType('in');

$filterGroup = $objectManager->create('\Magento\Framework\Api\Search\FilterGroup');
$filterGroup->setFilters([$filter]);

$filterEnabled = $objectManager->create('\Magento\Framework\Api\Filter');
$filterEnabled->setField('status');
$filterEnabled->setValue(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED);
$filterEnabled->setConditionType('eq');

$filterGroupEnabled = $objectManager->create('\Magento\Framework\Api\Search\FilterGroup');
$filterGroupEnabled->setFilters([$filterEnabled]);


$searchCriteria->setFilterGroups([$filterGroup, $filterGroupEnabled]);

In further details and logical combinations about search criteria, you can find at Magento-2 Search Criteria

5
  • This is incorrect. The logic is implemented on a per Repository basis. Jan 30, 2017 at 18:09
  • Hi @Alan Storm, this is tested solution. I have tested it for default store in Magento 2.1.0. Do you have any justification to declare it wrong, sir? Jan 30, 2017 at 18:46
  • @karnalsingh This bug: github.com/magento/magento2/issues/4287 Jan 30, 2017 at 18:52
  • @Alan Storm, that's what I have mentioned in my answer. All the Filter Groups are joined using AND operator and All the Filters in single Filter Group are joined using OR operator as per Magento 2 search criteria documentation. I have mentioned that this solution is tested with default store. What makes this answer wrong as per your comment, I did not get it. Jan 30, 2017 at 19:01
  • @KamelSingh Did you read the bug report I linked? Regardless of their intended behavior, the behavior of filters and filter groups is ultimately dependent on the behavior of the repository they're in. Jan 30, 2017 at 21:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.