0

In a custom module UpgradeSchema, I've this constructor :

function __construct(
    AttributeManagementInterfaceFactory $attributeManagementFactory,
) {
    $this->attributeManagementFactory = $attributeManagementFactory;
}

and this upgrade method :

public function upgrade( ModuleDataSetupInterface $setup, ModuleContextInterface $context ) {
    $attribute_id = 135;
    foreach([4, 9, 10] as $set_id) {
        // Get the attributes list for current attribute set
        $attributeManagement = $this->attributeManagementFactory->create();
        $attributes = $attributeManagement->getAttributes(\Magento\Catalog\Model\Product::ENTITY, $set_id);

        if($attributes[$attribute_id]) {
            var_dump($attributes[$attribute_id]->getAttributeSetId());
        }
    }
}

The product attribute with the id 135 is assign in three Attribute Sets (ids : 4, 9 and 10 in the foreach).

When I run the setup:upgrade, the var_dump outputs :

string(1) "4"
string(1) "4"
string(1) "4"

Three times the first Attribute Set ids, instead of 4, 9 and 10.

When I look into the AttributeManagement::getAttributes(), the load is called three times here :

$attributeCollection = $this->attributeCollection
    ->setAttributeSetFilter($attributeSet->getAttributeSetId())
    ->load();

return $attributeCollection->getItems();

But into the load method called (Magento\Framework\Data\Collection\AbstractDb::load()), Magento check if the collection is loaded (and returns the collection) or not (and so goes on) :

public function load($printQuery = false, $logQuery = false)
{
    if ($this->isLoaded()) {
        return $this;
    }

    return $this->loadWithFilter($printQuery, $logQuery);
}

I can't understand why, but it's a fact that the collection is not flagged as loaded the first time (hopefully) and flagged to true the two others times Magento check. And that despite I create new object in the foreach of my Upgrade script :

$attributeManagement = $this->attributeManagementFactory->create();

Someone to explains this phenomenon ? Or/And to explains how to fix it ?

0

In the constructor of the class AttributeManagement, the collection is injected like that :

public function __construct(
    ...
    \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection $attributeCollection,
    ...
) {
    ...
    $this->attributeCollection = $attributeCollection;
    ...
}

In other words, we inject a \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection singleton. And when a singleton is injected, it will be this same object (not a new one) wherever you will inject it again : in the same class, in an other class, etc... And I had a lack of knowledge about that.

So when, in my example, I recreate a new object AttributeManagement which inject Collection singleton in its own constructor, in fact it get the already created Collection singleton, with already items loaded, already filters added and everything...

Conclusion : Collection should be injected thanks to the Factory pattern :

public function __construct(
    ...
    \Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory $attributeCollectionFactory,
    ...
) {
    ...
    $this->attributeCollectionFactory = $attributeCollectionFactory;
    ...
}

And that change just a little where it's called

public function getAttributes($entityType, $attributeSetId)
{
    ...
    $attributeCollection = $this->attributeCollectionFactory->create();
    return $attributeCollection
        ->setAttributeSetFilter($attributeSet->getAttributeSetId())
        ->load()
        ->getItems();
}

And that works. But, that would be rewrite the core and it's forbidden. So I will not use the current getAttributes() method but I will copy and paste my solution directly in my upgrade method.

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.