3

Can anyone tell me how can i get product collection with filters? I'm use magento 2 sample data now. So i'm trying to get in product collection like selected on picture enter image description here with attribure style=backpack and activity=yoga; My code:

$productcollection = $objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Collection')
        ->addAttributeToSelect('style_bags','activity')
        ->addAttributeToFilter(
            array(
                array('attribute'=>'style_bags','eq'=>24),
                array('attribute'=>'activity','eq'=>8)
            )
        );

echo $productcollection->count();

But i'm get 4 products instead 2. But if i'll live only

array('attribute'=>'style_bags','eq'=>24)

without

array('attribute'=>'activity','eq'=>8)

it will works correct.

Can anyoune explain me how it works? Thank you.

UPD: It's seems to me, that in that case products selects with OR condition. But i need AND. If i change my code to

$productcollection = $objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Collection')
            ->addAttributeToSelect('style_bags','activity')
            ->addAttributeToFilter('style_bags',['eq'=>24])
            ->addAttributeToFilter('activity',['eq'=>8]);

I'ce got emty set.

5

1) We can print the sql with getSelect()

echo $productcollection->getSelect();

2) Add attribute filter to collection vendor/magento/module-eav/Model/Entity/Collection/AbstractCollection::addAttributeToFilter():

If $attribute is an array, it will add OR condition with the following format:

 array(
     array('attribute'=>'firstname', 'like'=>'test%'),
     array('attribute'=>'lastname', 'like'=>'test%'),
  )

vendor/magento/module-eav/Model/Entity/Collection/AbstractCollection::addAttributeToFilter()

    if (is_array($attribute)) {
        $sqlArr = [];
        foreach ($attribute as $condition) {
            $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType);
        }
        $conditionSql = '(' . implode(') OR (', $sqlArr) . ')';

So, as you said, your fist case will add OR condition.

There is a note when adding Eav attribute filter to collection. Take a look eav_attribute table, we can select color attribute:

SELECT * FROM eav_attribute e WHERE e.attribute_code = 'color';
  • backend_type is int - We can find the values in catalog_product_entity_int table. We use the values in our collection.
  • frontend_input is select - The value of this field to set type of frontend field type.

    $collection = $objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Collection');
    $productcollection =
        $collection->addAttributeToSelect('*')
                ->addAttributeToFilter(
                    [
                        //['attribute'=>'type_id','neq'=> 'simple'],
                        ['attribute'=>'color','eq'=> 4] // Color filter
                    ]
                );
    
    
    echo $productcollection->getSelect();
    

In your case, you should check the backend_type again.

3) You also can try with the Service Contracts Layer

Your construct:

 protected $_productRepository;

protected $_searchCriteriaBuilder;

public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
    \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
) {
    $this->_productRepository = $productRepository;
    $this->_searchCriteriaBuilder = $searchCriteriaBuilder;
}

In your custom method:

$searchCriteria = $this->_searchCriteriaBuilder->addFilter('color', 4, 'eq')->create();
$searchResults = $this->_productRepository->getList($searchCriteria);
$products = $searchResults->getItems();
3

You should use Search Criteria for filter collections.
It is better way (and correct) to filter collections in Magento2.
Go to http://alanstorm.com/magento_2_understanding_object_repositories/ and search for "Search Criteria" section ;)

It is not so hard to use it.

  • i tried, but it's not work. Still empty set result when i try to add style_bags AND acivity filters. – Illia Arefyev Mar 14 '17 at 13:38
  • How have you tried it? are you sure that those attributes are saved property in products? – Konrad Siamro Mar 15 '17 at 7:31
2

My answer is based on Konrad Siamro's answer and http://alanstorm.com/magento_2_understanding_object_repositories/

Here's what I do and it seems to be working:

<?php
namespace Company\ModName\Model;

class Helper
{
    protected $pageRepository;
    protected $productRepository;
    protected $filterBuilder;
    protected $filterGroupBuilder;
    protected $searchCriteriaBuilder;
    protected $objectManager;
    protected $_productAttributeRepository;


    public function __construct(
        \Magento\Cms\Model\PageRepository $pageRepository,
        \Magento\Catalog\Model\ProductRepository $productRepository,
        \Magento\Framework\Api\FilterBuilder $filterBuilder,
        \Magento\Framework\Api\Search\FilterGroupBuilder $filterGroupBuilder,
        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
        \Magento\Framework\ObjectManagerInterface $objectManager,
        \Magento\Catalog\Model\Product\Attribute\Repository $productAttributeRepository
    )
    {
        $this->pageRepository = $pageRepository;
        $this->productRepository = $productRepository;
        $this->filterBuilder = $filterBuilder;
        $this->filterGroupBuilder = $filterGroupBuilder;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->objectManager = $objectManager;
        $this->_productAttributeRepository = $productAttributeRepository;
    }

    private function returnProdCollectBasedOnYearAndMake($yearOptionCode, $makeOptionCode)
    {
        $yearOptionId = $this->getOptionId('year', $yearOptionCode);
        $makeOptionId = $this->getOptionId('make', $makeOptionCode);

        $filter_1 = $this->filterBuilder
            ->setField('make')
            ->setConditionType('eq')
            ->setValue($makeOptionId)
            ->create();

        $filter_2 = $this->filterBuilder
            ->setField('year')
            ->setConditionType('eq')
            ->setValue($yearOptionId)
            ->create();

        $filter_group_1 = $this->filterGroupBuilder
            ->addFilter($filter_1)
            ->create();

        $filter_group_2 = $this->filterGroupBuilder
            ->addFilter($filter_2)
            ->create();

        $search_criteria = $this->searchCriteriaBuilder
            ->setFilterGroups([$filter_group_1, $filter_group_2])
            ->create();

        $repo = $this->productRepository;
        $result = $repo->getList($search_criteria);
        $products = $result->getItems();
        foreach($products as $product)
        {
            echo $product->getSku() . "<br>";
        }

        return $products;
    }

    private function getOptionId($attributeCode, $optionLabel)
    {
        $options = $this->_productAttributeRepository->get($attributeCode)->getOptions();
        foreach ($options as $option) {
            if ($optionLabel === $option->getLabel()) {
                return $option->getValue();
            }
        }
        return -1;
    }
}
0

/gear/bags.html?activity=8&style_bags=28

I am getting 3 records in frontend but from code level, I am getting 4 records. My code is

$productCollection = 
$objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Collection')
              ->addAttributeToSelect('*')
              ->addAttributeToFilter(
                 [
                    ['attribute'=>'style_bags','in'=> 28], // style bags filter
                    ['attribute'=>'activity','in'=> 8] // activity filter
                 ]
           );

 print_r($productCollection->getData());
 die();

It would be kind if you help me out in solving this issue. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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