Magento 2: Repozytoria produktów, grupy filtrów i `AND`

12

Próbuję użyć repozytorium produktów, aby pobrać listę produktów. Chcę pobierać na podstawie dwóch filtrów w połączeniu z ANDkryteriami, ale wydaje się, że nie działają. Czy nie rozumiem, jak działają grupy filtrów? Czy jest to błąd, który należy zgłosić?

W szczególności (głupi przykład dla uproszczenia) Mam konstruktora, do którego wprowadzam konstruktor filtrów, konstruktor grup filtrów i konstruktor kryteriów wyszukiwania

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

Następnie, w metodzie, używam konstruktorów filtrów, aby zbudować dwa filtry

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

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

Następnie używam konstruktora grup filtrów, aby zbudować grupę filtrów, która składa się z tych dwóch filtrów

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

Następnie użyłem konstruktora kryteriów wyszukiwania, ustaw na nim grupę filtrów

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

Wreszcie, kiedy używam tych kryteriów z repozytorium produktów (używane gdzie indziej, pomijając konstruktora i di, aby uniknąć pomyłek)

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

Połączenie jest udane, ale otrzymuję dwa produkty. tzn. filtr SKU został zastosowany jako a ORnie AND. Spodziewałbym się, że to zapytanie nic nie zwróci.

Jeśli zagłębię się w Magento\Catalog\Api\ProductRepositoryklasę i spojrzę na wybraną kolekcję

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

Widzę kryteria dodane z 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')) 

Czy to błąd? Czy istnieje sposób (bez polegania bezpośrednio na kolekcjach produktów i porzucaniu repozytoriów), aby to zadziałało?

Alan Storm
źródło
2
Nie badałem jeszcze tego obszaru osobiście, ale cyrillschumacher.com/2015/01/02/… może być przydatny.
Alan Kent

Odpowiedzi:

15

Rzeczywista adnotacja \Magento\Framework\Api\Search\FilterGroupmówi (klasa phpDoc):

Grupuje dwa lub więcej filtrów razem za pomocą logicznej OR

Oznacza to, że musisz utworzyć dwie grupy z jednym filtrem w każdej.

Alex Paliarush
źródło
Dzięki za wyjaśnienie tego. Właśnie pokochałeś wszystkie warstwy abstrakcji w Magento 2 :-P
Giel Berkers
2

W Magento 2 wszystkie filtry w tym samym FilterGroupzostaną dodane za pomocą ORoperatora. Ale wszystkie FilterGroupzostaną dodane za pomocą ANDoperatora. Musisz dodać wiele FilterGroups, jak poniżej:

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

Dalsze szczegóły i logiczne kombinacje kryteriów wyszukiwania można znaleźć na stronie Magento-2 Search Criteria

Kamal Singh
źródło
To jest niepoprawne. Logika jest implementowana dla poszczególnych repozytoriów.
Alan Storm,
Cześć @Alan Storm, to sprawdzone rozwiązanie. Przetestowałem to dla domyślnego sklepu w Magento 2.1.0. Czy ma pan jakieś uzasadnienie, by uznać to za złe, proszę pana?
Kamal Singh
@karnalsingh Ten błąd: github.com/magento/magento2/issues/4287
Alan Storm
@Alan Storm, o tym wspomniałem w mojej odpowiedzi. Wszystkie grupy filtrów są połączone za pomocą operatora AND, a wszystkie filtry w jednej grupie filtrów są połączone za pomocą operatora OR zgodnie z dokumentacją kryteriów wyszukiwania Magento 2. Wspomniałem, że to rozwiązanie jest testowane w domyślnym sklepie. Co sprawia, że ​​ta odpowiedź jest zła, jak na twój komentarz, nie rozumiem.
Kamal Singh
@KamelSingh Czy przeczytałeś raport o błędzie, który dowiązałem? Niezależnie od ich zamierzonego zachowania zachowanie filtrów i grup filtrów zależy ostatecznie od zachowania repozytorium, w którym się znajdują.
Alan Storm