Skip to content

Magento\CatalogImportExport\Model\Import\Product\CategoryProcessor Failed categories aren't removed from the categories returned by upsertCategories #17588

Closed
@simonworkhouse

Description

@simonworkhouse

The function upsertCategories may return a category id that is no longer present in the DB as upsertCategory on line 138 of Magento\CatalogImportExport\Model\Import\Product\CategoryProcessor fetches the category id from the local class cache ($this->categories) of the available categories.
This causes the import to fail if the category was inserted, added to the cache and then removed from the DB due to either a transaction being rolled back or the category being automatically deleted.
Transactions in this instance are probably being rolled back due to url_key conflicts.

Preconditions

  1. Magento 2.2.5
  2. PHP 7.1.20
  3. MySQL 5.7.23

Steps to reproduce

My best guess is that transactions are being rolled back due to url_key conflicts.
Refer to the issue #17586 for clarification on how to set up import data that will have unexpected URL rewrite conflicts.
It would take quite a bit of time to set up a full procedure, but let me know if it's absolutely required.
It should be obvious enough for anyone reviewing the code and referring to the previous bug report #17586

I have implemented a work-around for now, but this needs to be addressed and fixed in the core.

<?php

namespace {my_namespace}\Plugin\Magento\CatalogImportExport\Model\Import\Product;

use Magento\CatalogImportExport\Model\Import\Product\CategoryProcessor;

class CategoryProcessorPlugin
{
    /**
     * // NOTE: Must cache the failed categories here as Magento caches them even if they have failed and as 
     *          a result won't add them to the failed categories list
     * @var array
     */
    protected static $failedCategoriesCache = [];

    /**
     * [afterUpsertCategories description]
     * @param  CategoryProcessor $categoryProcessor [description]
     * @param  [type]            $categoryIds       [description]
     * @return [type]                               [description]
     */
    public function afterUpsertCategories(CategoryProcessor $categoryProcessor, $categoryIds)
    {
        // NOTE: Work-around for a Magento bug where it's still adding failed categories to the list
        if ($failedCategories = $categoryProcessor->getFailedCategories()) {
            foreach ($failedCategories as $failedCategory) {
                self::$failedCategoriesCache[] = $failedCategory['category']->getId();
            }
        }
        $categoryIds = array_diff($categoryIds, self::$failedCategoriesCache);
        return $categoryIds;
    }
}

Expected result

The function upsertCategories should only ever return categories that actually exist.

Actual result

The function upsertCategories returns categories from the local class cache that have since been removed from the DB during the same import run.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions