magento2: Bug - Magento_Eav - eav_attribute_group (repository) filtering

There is a bug on the Magento_Eav Module, to be more precise, there is a bug when you want to filter the attribute_group collection by multiple values (IN).

*The bug affects rest api too

Preconditions (*)

  1. Any Magento 2.3.1 that does not overwrite Magento_Eav module
  2. Some data on the site, I tested with sampledata

Steps to reproduce (*)

  1. Try to filter the eav_attribute_group (AttributeGroupRepository) by multiple attribute_set_id’s or by multiple attribute_group_code

If you try to filter by attribute_group_code, you won’t be able to filter at all.

/**
 * @var \Magento\Eav\Api\AttributeGroupRepositoryInterface
 */
protected $attributeGroupRepository;

/**
 * @var \Magento\Framework\Api\Search\SearchCriteriaBuilderFactory
 */
protected $searchCriteriaBuilderFactory;

/**
 * @var \Magento\Framework\Api\FilterBuilder
 */
protected $filterBuilder;

public function __construct(
    \Magento\Eav\Api\AttributeGroupRepositoryInterface $attributeGroupRepository,
    \Magento\Framework\Api\Search\SearchCriteriaBuilderFactory >$searchCriteriaBuilderFactory,
    \Magento\Framework\Api\FilterBuilder $filterBuilder
) {
    $this->attributeGroupRepository = $attributeGroupRepository;
    $this->searchCriteriaBuilderFactory = $searchCriteriaBuilderFactory;
    $this->filterBuilder = $filterBuilder;
}

public function test()
{
    /** @var \Magento\Framework\Api\Search\SearchCriteriaBuilder $criteriaBuilder */
    $criteriaBuilder = $this->searchCriteriaBuilderFactory->create();
    $setIdFilter = $this->filterBuilder
        ->setField('attribute_set_id')
        ->setValue('15,10,4,14,11,12,13,9') // All the attribute_set_id from that are present on clean install with sampledata
        ->setConditionType('in')
        ->create();

    $groupCodeFilter = $this->filterBuilder
        ->setField('attribute_group_code')
        ->setValue('"advanced-pricing", "autosettings", "bundle-items", "content"')
        ->setConditionType('in')
        ->create();

/* I am using directly imploded strings because this is the format I need when I am doing rest api 
   get, and since is the same repository, it works the same way.*/

    $criteria = $criteriaBuilder->addFilter($setIdFilter)->create();
    //$criteria = $criteriaBuilder->addFilter($groupCodeFilter)->create();

    $groupList = $this->attributeGroupRepository->getList($criteria);
    //Do something with $groupList
    var_dump($groupList->getSearchCriteria()->getFilterGroups()[0]->getFilters());
    var_dump($groupList->getTotalCount());
    foreach ($groupList->getItems() as $group) {
        var_dump('AttributeSetId: ' . $group->getAttributeSetId());
    }
    die('asdfasfasdf');
}

Expected result (*)

  1. Returning all the groups assigned to all the attribute_set_id’s given. In the database, that means, 80 records (sampledata)

select

Actual result (*)

    ....php:102:
    array (size=1)
   0 => 
     object(Magento\Framework\Api\Filter)[1784]
       protected '_data' => 
         array (size=3)
           'field' => string 'attribute_set_id' (length=16)
           'value' => string '15,10,4,14,11,12,13,9' (length=21)
           'condition_type' => string 'in' (length=2)
     ....php:103:int 10
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)
     ....php:105:string 'AttributeSetId: 15' (length=18)

The query string after applying the filters:

 SELECT `main_table`.* FROM `eav_attribute_group` AS `main_table` WHERE (`attribute_set_id` = '15,10,4,14,11,12,13,9')

The problem, as I said in some other post (https://github.com/magento/magento2/issues/2892#issuecomment-499893836) is:

After some debugging, I found the problem: When the AttributeGroupRepository processes the collection, the process goes through:

vendor/magento/framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php
    addFilterGroupToCollection(...)

Here, on the line 66-70:

        $customFilter = $this->getCustomFilterForField($filter->getField());
        if ($customFilter) {
            $isApplied = $customFilter->apply($filter, $collection);
        }

There IS a custom field for my search (attribute_set_id), and the code goes in:

 vendor/magento/module-eav/Model/Api/SearchCriteria/CollectionProcessor/FilterProcessor/AttributeGroupAttributeSetIdFilter.php

Here there is:

public function apply(Filter $filter, AbstractDb $collection)
{
    /** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\Collection $collection */
    $collection->setAttributeSetFilter($filter->getValue());

    return true;
}

Which goes on:

 vendor/magento/module-eav/Model/ResourceModel/Entity/Attribute/Group/Collection.php
public function setAttributeSetFilter($setId)
{
    $this->addFieldToFilter('attribute_set_id', ['eq' => $setId]);
    $this->setOrder('sort_order');
    return $this;
}

Here we can see that the eav_attribute_group collection does not even care about what we want us to do with the filter, it simply forces us on equal.

I don’t want to believe that this was intentional, but instead, I believe that this was some old code that was done before the whole process-filter-thing, and it was forgotten.

The same goes for all filters from the eav_attribute_group:

      vendor/magento/module-eav/Model/Api/SearchCriteria/CollectionProcessor/FilterProcessor/AttributeGroupAttributeSetIdFilter.php
vendor/magento/module-eav/Model/Api/SearchCriteria/CollectionProcessor/FilterProcessor/AttributeGroupCodeFilter.php
vendor/magento/module-eav/Model/Api/SearchCriteria/CollectionProcessor/FilterProcessor/AttributeSetEntityTypeCodeFilter.php

All of them, don’t bother to see what condition type we want to use on the collection.

For fixes, I think that the best solution is to let the processor do its job. That means:

vendor/magento/module-eav/etc/di.xml

Remove the lines 184-154:

<virtualType name="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\AttributeSetFilterProcessor" type="Magento\Framework\Api\SearchCriteria\CollectionProcessor\FilterProcessor">
    <arguments>
        <argument name="customFilters" xsi:type="array">
            <item name="entity_type_code" xsi:type="object">Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor\AttributeSetEntityTypeCodeFilter</item>
        </argument>
    </arguments>
</virtualType>

Remove the lines: 169-179

<virtualType name="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\AttributeGroupFilterProcessor" type="Magento\Framework\Api\SearchCriteria\CollectionProcessor\FilterProcessor">
    <arguments>
        <argument name="fieldMapping" xsi:type="array">
            <item name="attribute_group_code" xsi:type="string">main_table.attribute_group_code</item>
        </argument>
        <argument name="customFilters" xsi:type="array">
            <item name="attribute_set_id" xsi:type="object">Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor\AttributeGroupAttributeSetIdFilter</item>
            <item name="attribute_group_code" xsi:type="object">Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor\AttributeGroupCodeFilter</item>
        </argument>
    </arguments>
</virtualType>

And of course, remove the not used (anymore) code…

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 17 (5 by maintainers)

Most upvoted comments

@magento-engcom-team Yes, I can reproduce it on multiple instances of 2.3.1 Can somebody work on this? There is a little problem because I need to do api requests, and by doing N requests to get some attribute groups is really… inneficient, nobody wants to wait 10-20 seconds just to do some checks on the other end…