Magento 2: repositorios de productos, grupos de filtros y `AND`

12

Estoy tratando de usar un repositorio de productos para obtener una lista de productos. Quiero obtener en función de dos filtros, combinados con un ANDcriterio, pero las cosas no parecen funcionar. ¿No entiendo cómo funcionan los grupos de filtros? ¿O se trata de un error que se debe informar?

Específicamente, (ejemplo tonto por simplicidad) tengo un constructor donde inyecto un generador de filtros, un generador de grupos de filtros y un generador de criterios de búsqueda

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

Luego, más adelante en un método, uso los creadores de filtros para construir dos filtros

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

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

Luego uso el generador de grupos de filtros para crear un grupo de filtros que consta de estos dos filtros

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

Luego usé un generador de criterios de búsqueda, configuré el grupo de filtros

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

Finalmente, cuando uso este criterio con un repositorio de productos (usado en otro lugar, omitiendo constructor y di para evitar confusiones)

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

La llamada es exitosa pero recibo dos productos. es decir, el filtro SKU se aplicó como a OR, no como AND. Espero que esta consulta no devuelva nada.

Si profundizo en la Magento\Catalog\Api\ProductRepositoryclase y miro la declaración selecta de la colección

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

Veo los criterios agregados con un 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')) 

¿Es esto un error? ¿Hay alguna manera (salvo depender directamente de las colecciones de productos y deshacerse de los repositorios) para que esto funcione?

Alan Storm
fuente
2
Todavía no he examinado esta área personalmente, pero cyrillschumacher.com/2015/01/02/… podría ser útil.
Alan Kent

Respuestas:

15

Anotación real de \Magento\Framework\Api\Search\FilterGroupsay (clase phpDoc):

Agrupa dos o más filtros mediante un OR lógico

Significa que necesita crear dos grupos con un filtro en cada uno.

Alex Paliarush
fuente
Gracias por aclarar esto. Solo tienes que amar todas las capas de abstracción en Magento 2
:-P
2

En Magento 2, todos los filtros en el mismo FilterGroupse agregarán utilizando el ORoperador. Pero todo FilterGroupse agregará utilizando el ANDoperador. Por lo tanto, deberá agregar varios FilterGroups como se muestra a continuación:

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

En más detalles y combinaciones lógicas sobre los criterios de búsqueda, puede encontrar en Magento-2 Search Criteria

Kamal Singh
fuente
Esto es incorrecto. La lógica se implementa por repositorio.
Alan Storm
Hola @ Alan Storm, esta es una solución probada. Lo he probado para la tienda predeterminada en Magento 2.1.0. ¿Tiene alguna justificación para declararlo mal, señor?
Kamal Singh
@karnalsingh Este error: github.com/magento/magento2/issues/4287
Alan Storm
@ Alan Storm, eso es lo que he mencionado en mi respuesta. Todos los grupos de filtros se unen usando el operador AND y todos los filtros en un solo grupo de filtros se unen usando el operador OR según la documentación de criterios de búsqueda de Magento 2. He mencionado que esta solución se prueba con la tienda predeterminada. Lo que hace que esta respuesta sea incorrecta según su comentario, no lo entendí.
Kamal Singh
@KamelSingh ¿Leíste el informe de error que vinculé? Independientemente de su comportamiento previsto, el comportamiento de los filtros y grupos de filtros depende en última instancia del comportamiento del repositorio en el que se encuentran.
Alan Storm