Magento2 Product Attribute Collection – Filter Product Collection by SKU or Name

collection;filtermagento2product-attribute

I have a variable which containing value to filter both name or sku, i tried to filter the product collection using this variable like this:

$queryName = 'bat';
$category = $this->_categoryFactory->create()->load('2');
$collection = $this->_productCollectionFactory->create();
$collection->addAttributeToSelect('*');
$collection->addCategoryFilter($category);
$collection->addAttributeToFilter(['name', 'sku'],
          [
           ['like' => '%'.$queryName.'%'],
           ['like' => '%'.$queryName.'%']
          ]);
$collection->setPage(1,15)->load();
return $collection;

but i got an error like this:

Warning: Illegal string offset 'attribute' in
/../vendor/magento/module-eav/Model/Entity/Collection/AbstractCollection.php
on line 362

Best Answer

The syntax for addAttributeToFilter() that you are using was possible in Magento 1, but in Magento 2 there is only one way to use the method to add multiple filters with OR, namely with a single argument:

$collection->addAttributeToFilter(
      [
       ['attribute' => 'name', 'like' => '%'.$queryName.'%'],
       ['attribute' => 'sku', 'like' => '%'.$queryName.'%']
      ]);

That's why you get this error message: Magento expects an array, where you pass 'name' and 'sku'. And while you can use square brackets to access characters in a string ('name'[0]), a non-numeric index as in 'name'['attribute'] throws an error.


Service contracts

You might wonder, if you can achieve the same using the product repository instead of collections, which is the recommended and more upgrade safe way. Repositories are part of the @api service contract of each module and are treated carefully regarding backwards compatibility, while collections are an implementation detail which will not stay the same in the long run.

If it's possible to achieve what you need with repositories, you should do it (see: When Should We Use a Repository and Factory in Magento 2?))

In this case, it's too complicated and imperformant (as of ):

  • There's Magento\Catalog\Api\CategoryLinkManagementInterface::getAssignedProducts() to retrieve a sorted list of SKUs for a given category id, but it does not accept additional filters
  • You cannot use the filter argument of Magento\Catalog\Api\ProductRepositoryInterface::getList() for the category, because it is not an attribute, but an external n:m relation.

So it would require two steps:

  1. load all skus for the category with CategoryLinkManagementInterface::getAssignedProducts().

  2. use ProductRepositoryInterface::getList() to get a list of products with filter conditions:

    • SKU in (previous result) AND
    • (your additional filters)
Related Topic