4

In Magento 2, it's not possible to add a store_id filter to a product collection directly. Instead, you need to use the addStoreFilter method, which adds a special "product limitation filter". It appears that addFieldToFilter is meant for attributes specific to a particular collection, and the product limitation filters are meant for attributes that might be shared globally across collections (store_id, website_id, category_id, etc).

Given that, is is possible to create a filter for a product repository to get a list of products filtered by store_id? Attempting to use a filter like this with a repository

/* @var $filterBuilder \Magento\Framework\Api\FilterBuilder */
$this->filterBuilder->setField('store_id')
    ->setValue('1')
    ->setConditionType('eq')
    ->create();

produces the following error

Invalid attribute name: store_id

i.e. the repository attempts to create a filter on the underlying collection with the addFieldToFilter method.

1 Answer 1

4

Bug is created to add filtration capability by store ID, see this response.

The following plugin can be used as a workaround before the issue is fixed in the core. It allows to avoid hacks in the core code and will not break your installation even after this issue is fixed.

Add plugin declaration in the global area, VendorName/ModuleName/etc/di.xml

<type name="Magento\Catalog\Model\ResourceModel\Product\Collection">
    <plugin name="storeFilterFixer" type="VendorName\ModuleName\Model\Plugin\StoreFilterFixer" />
</type>

Create class VendorName/ModuleName/Model/Plugin/StoreFilterFixer.php

<?php
namespace VendorName\ModuleName\Model\Plugin;

use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;

/**
 * This plugin fixes issue with filtration by store/website ID in \Magento\Catalog\Model\ProductRepository::getList()
 */
class StoreFilterFixer
{
    /**
     * Enable filtration by store_id or website_id. The only supported condition is 'eq'
     *
     * @param ProductCollection $subject
     * @param \Closure $proceed
     * @param array $fields
     * @param string|null $condition
     * @return ProductCollection
     */
    public function aroundAddFieldToFilter(ProductCollection $subject, \Closure $proceed, $fields, $condition = null)
    {
        if (is_array($fields)) {
            foreach ($fields as $key => $filter) {
                if ($filter['attribute'] == 'website_id' && isset($filter['eq'])) {
                    $subject->addWebsiteFilter([$filter['eq']]);
                    unset($fields[$key]);
                } else if ($filter['attribute'] == 'store_id' && isset($filter['eq'])) {
                    $subject->addStoreFilter($filter['eq']);
                    unset($fields[$key]);
                }
            }
        }
        /** Do not try to pass empty $fields to addFieldToFilter, it will cause exception */
        return $fields? $proceed($fields, $condition) : $subject;
    }
}
3
  • Thank you for your answer, but I'm not sure I follow that completely. Are you saying the repository will always set the ID of the product based on the current store? If so, what happens if I'm in store X, and the underlying product collection returns an item that's not in store X — will its store ID be overridden (and therefore incorrect?) Nov 23, 2015 at 23:08
  • @AlanStorm You are right. My initial response addressed issues with data representation in the context of particular store, not data filtration. Please see revised answer. Nov 24, 2015 at 22:39
  • @AlexPaliarush - This solution not working in magento2.3.2 Jul 21, 2021 at 19:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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