Magento 2: Repositórios de Produtos, Grupos de Filtros e `AND`

12

Estou tentando usar um repositório de produtos para buscar uma lista de produtos. Quero buscar com base em dois filtros, combinados com umAND critério, mas as coisas parecem não estar funcionando. Não entendo como os grupos de filtros funcionam? Ou isso é um bug que deve ser relatado?

Especificamente, (exemplo bobo por uma questão de simplicidade) eu tenho um construtor em que injeto um construtor de filtros, um construtor de grupos de filtros e um construtor de critérios de pesquisa

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

Mais tarde, em um método, eu uso os construtores de filtros para criar dois filtros

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

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

Então eu uso o construtor de grupos de filtros para criar um grupo de filtros que consiste nesses dois filtros

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

Então eu usei um construtor de critérios de pesquisa, defina o grupo de filtros nele

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

Finalmente, quando eu uso esse critério com um repositório de produtos (usado em outro lugar, deixando de fora construtor e di para evitar confusão)

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

A ligação é bem-sucedida, mas recebo de volta dois produtos. ou seja, o filtro SKU foi aplicado como umOR , não um AND. Eu esperaria que esta consulta não retornasse nada.

Se eu entrar na Magento\Catalog\Api\ProductRepositoryturma e dar uma olhada na declaração de seleção da coleção

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

Vejo os critérios adicionados com um 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')) 

Isso é um inseto? Existe uma maneira (além de confiar diretamente nas coleções de produtos e abandonar os repositórios) para fazer isso funcionar?

Alan Storm
fonte
2
Ainda não examinei pessoalmente essa área, mas cyrillschumacher.com/2015/01/02/… pode ser útil.
Alan Kent

Respostas:

15

Anotação real de \Magento\Framework\Api\Search\FilterGroupsays (classe phpDoc):

Agrupa dois ou mais filtros usando um OR lógico

Isso significa que você precisa criar dois grupos com um filtro em cada um.

Alex Paliarush
fonte
Obrigado por esclarecer isso. Você apenas tem que amar todas as camadas de abstração em Magento 2 :-P
Giel Berkers
2

No Magento 2 todos os filtros FilterGroupserão adicionados usando o ORoperador. Mas tudo FilterGroupserá adicionado usando o ANDoperador. Então, você precisará adicionar vários FilterGroups como abaixo:

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

Em mais detalhes e combinações lógicas sobre os critérios de pesquisa, você pode encontrar em Critérios de pesquisa do Magento-2

Kamal Singh
fonte
Isto está incorreto. A lógica é implementada em uma base por repositório.
Alan Storm.
Olá, Alan Storm, esta é uma solução testada. Eu testei para a loja padrão no Magento 2.1.0. Você tem alguma justificativa para declara-lo errado, senhor?
Kamal Singh
@karnalsingh Este bug: github.com/magento/magento2/issues/4287
Alan Storm
@ Alan Storm, foi o que mencionei na minha resposta. Todos os grupos de filtros são unidos usando o operador AND e todos os filtros em um único grupo de filtros são unidos usando o operador OR, conforme a documentação dos critérios de pesquisa do Magento 2. Mencionei que esta solução é testada com o armazenamento padrão. O que torna esta resposta errada de acordo com o seu comentário, eu não entendi.
Kamal Singh
@KamelSingh Você leu o relatório de bug que vinculei? Independentemente do seu comportamento a que se destina, o comportamento dos filtros e grupos de filtro é, em última análise dependente do comportamento do repositório que eles estão em.
Alan Storm