akeneo / magento2-connector-community

Akeneo Connector for Magento 2
Open Software License 3.0
81 stars 88 forks source link

Categories matched by rule are not handled at all #635

Open bartoszkubicki opened 1 year ago

bartoszkubicki commented 1 year ago

Environment and configuration

  1. 100.4.16 - but haven't found fixes or handling for given issue in changelog

Steps to reproduce

  1. Configure categories matched rule (by attribute for example) image
  2. Have corresponding categories in akeneo (empty)
  3. Import products
  4. Check if products are correctly assigned to categories

Expected result

  1. Products are assigned according to rules

Actual result

  1. Categories that matches products by rules are wiped out or products count is lower (if we exclude some families from import)

Issue was solved by out team with following plugin:

use Akeneo\Connector\Job\Product;
use Exception;
use Magento\Catalog\Model\Category;
use Magento\Catalog\Model\ResourceModel\Category as CategoryResource;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\VisualMerchandiser\Model\Category\Builder;
use Magento\VisualMerchandiser\Model\ResourceModel\Rules\Collection as RulesCollection;
use Magento\VisualMerchandiser\Model\ResourceModel\Rules\CollectionFactory as RulesCollectionFactory;

class RebuildDynamicCategories
{
    private CategoryResource $categoryResource;
    private CategoryCollectionFactory $categoryCollectionFactory;
    private Builder $builder;
    private RulesCollectionFactory $rulesCollectionFactory;

    public function __construct(
        CategoryResource $categoryResource,
        CategoryCollectionFactory $categoryCollectionFactory,
        Builder $builder,
        RulesCollectionFactory $rulesCollectionFactory
    ) {
        $this->categoryResource = $categoryResource;
        $this->categoryCollectionFactory = $categoryCollectionFactory;
        $this->builder = $builder;
        $this->rulesCollectionFactory = $rulesCollectionFactory;
    }

    public function afterSetCategories(Product $subject, $result)
    {
        $this->rebuildDynamicCategories($subject);
        return $result;
    }

    private function rebuildDynamicCategories(Product $productImport): void
    {
        $rulesCollection = $this->rulesCollectionFactory->create();
        /** @var $rulesCollection RulesCollection */
        $rulesCollection->addFieldToFilter('is_active', ['eq' => 1]);
        $categoriesIds = $rulesCollection->getColumnValues('category_id');

        $categoryCollection = $this->categoryCollectionFactory->create();
        $categoryCollection->addAttributeToSelect('*')
            ->addFieldToFilter($this->categoryResource->getEntityIdField(), ['in' => $categoriesIds]);

        foreach ($categoryCollection as $category) {
            $this->builder->rebuildCategory($category);
            $this->saveRebuiltCategory($productImport, $category);
        }
    }

    private function saveRebuiltCategory(Product $productImport, Category $category): void
    {
        try {
            $this->categoryResource->save($category);
        } catch (Exception $exception) {
            $productImport->setAdditionalMessage(
                __(
                    'Dynamic category %1 (ID: %2) couldn\'t be rebuilt correctly',
                    $category->getName(),
                    $category->getId()
                )
            );
        }
    }
}
oefterdal commented 9 months ago

@bartoszkubicki we have the same issue. Could you team make a pull request so this could hopefully end up in a future release?

bartoszkubicki commented 4 months ago

@magentix I can see a proposal of my fix for the given issue has been added. Unfortunately, I can see you have removed two dependencies from the constructor method and you are pulling them from the object manager. This is a clear antipattern and I have no idea why you did that. Please fix it or remove my name from that class. I don't want to be linked with such poor-quality code.

magentix commented 4 months ago

@bartoszkubicki

We must be compatible with all Magento versions, the use of VisualMerchandiser classes in the constructor breaks all Magento OpenSource / OpenMage and Adobe Commerce without the module.

Note that the plugin was removed in 104.0.7 (the product sort order is not persisted with this technique).

https://github.com/akeneo/magento2-connector-community/commit/34f65b7aecb2b22c66bbc6c67d5a02542c7ccf3e