Magento 2: хранилища продуктов, группы фильтров и `AND`

12

Я пытаюсь использовать репозиторий продуктов, чтобы получить список продуктов. Я хочу получить данные на основе двух фильтров в сочетании с ANDкритериями, но, похоже, что-то не работает. Я не понимаю, как работают группы фильтров? Или это ошибка, о которой нужно сообщить?

В частности, (глупый пример для простоты) у меня есть конструктор, в который я вставляю построитель фильтров, построитель групп фильтров и построитель критериев поиска

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;
}

Затем, позже в методе, я использую построители фильтров для создания двух фильтров

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

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

Затем я использую построитель группы фильтров для создания группы фильтров, состоящей из этих двух фильтров.

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

Затем я использовал построитель критериев поиска, установил для него группу фильтров

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

Наконец, когда я использую этот критерий с репозиторием продукта (используется в другом месте, оставляя конструктор и di, чтобы избежать путаницы)

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

Звонок успешен, но я вернул два продукта. т.е. фильтр SKU был применен как, а ORне как AND. Я ожидаю, что этот запрос ничего не даст.

Если я покопаюсь в Magento\Catalog\Api\ProductRepositoryклассе и посмотрю на избранный устав коллекции

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;
}               

Я вижу критерии, добавленные с 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')) 

Это ошибка? Есть ли способ (если не полагаться непосредственно на коллекции продуктов и отказаться от репозиториев), чтобы сделать эту работу?

Алан Сторм
источник
2
Я еще не изучал эту область лично, но cyrillschumacher.com/2015/01/02/… может быть полезным.
Алан Кент

Ответы:

15

Фактическая аннотация \Magento\Framework\Api\Search\FilterGroupговорит (класс phpDoc):

Группирует два или более фильтров вместе, используя логическое ИЛИ

Это означает, что вам нужно создать две группы с одним фильтром в каждой.

Алекс Палиаруш
источник
Спасибо за разъяснение этого. Вы просто должны любить все слои абстракции в Magento 2 :-P
Гил Беркерс
2

В Magento 2 все фильтры FilterGroupбудут добавлены с помощью ORоператора. Но все FilterGroupбудет добавлено с помощью ANDоператора. Так что вам нужно будет добавить несколько FilterGroups, как показано ниже:

$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]);

Более подробную информацию и логические комбинации о критериях поиска вы можете найти в Magento-2 Критерии поиска.

Камаль Сингх
источник
Это неверно Логика реализована для каждого репозитория.
Алан Сторм
Привет @Alan Storm, это проверенное решение. Я проверил это для магазина по умолчанию в Magento 2.1.0. Есть ли у вас какие-либо основания объявлять это неправильно, сэр?
Камаль Сингх
@karnalsingh Эта ошибка: github.com/magento/magento2/issues/4287
Алан Шторм
@ Алан Шторм, вот что я упомянул в своем ответе. Все группы фильтров объединяются с помощью оператора AND, а все фильтры в одной группе фильтров объединяются с помощью оператора OR согласно документации по критериям поиска Magento 2. Я упомянул, что это решение протестировано с хранилищем по умолчанию. Что делает этот ответ неправильным согласно вашему комментарию, я не получил его.
Камаль Сингх
@KamelSingh Вы читали отчет об ошибке, который я связал? Независимо от их предполагаемого поведения, поведение фильтров и групп фильтров в конечном итоге зависит от поведения репозитория, в котором они находятся.
Alan Storm