Magento 2 Export products error

Magento 2 Export products error

Exporting your Magento 2.x data can sometimes be a tricky task. This is a common issue that happened after migration from Magento 1 to  Magento 2. You may face the absence of half of the information about products which happened during the export to the CSV file. For instance, only 10 of the (conditional) attributes were downloaded. And it is difficult to determine the reason why during the migration, not all attribute sets were transferred from the old store to the new one.

How to identify an error:

Incorrect CSV file formatting.

In the error log (exception.log) there is approximately such an error: main.CRITICAL: Notice: Undefined offset: 1 in /vendor/magento/module-catalog-import-export/Model/Export/Product.php on line 1030

The function in which the error occurred and its contents

<?php

/**

* Collect export data for all products

*

* @return array

* @SuppressWarnings(PHPMD.CyclomaticComplexity)

* @SuppressWarnings(PHPMD.NPathComplexity)

*/

protected function collectRawData()

{

   …

           if (!empty($data[$itemId][$storeId]) || $this->hasMultiselectData($item, $storeId)) {

               $attrSetId = $item->getAttributeSetId();

               $data[$itemId][$storeId][self::COL_STORE] = $storeCode;      

               $data[$itemId][$storeId][self::COL_ATTR_SET] = $this->_attrSetIdToName[$attrSetId];

               $data[$itemId][$storeId][self::COL_TYPE] = $item->getTypeId();

           }

           ….

       }

   }

   return $data;

}

?>

If you look at the level above (where this function is called), in case of an error, the initialization of the headers for the CVS file is terminated

<?php

$this->setHeaderColumns($multirawData[‘customOptionsData’], $stockItemRows);

?>

<?php

/**

* Get export data for collection

*

* @return array

* @SuppressWarnings(PHPMD.CyclomaticComplexity)

* @SuppressWarnings(PHPMD.NPathComplexity)

* @SuppressWarnings(PHPMD.ExcessiveMethodLength)

* @SuppressWarnings(PHPMD.UnusedLocalVariable)

*/

protected function getExportData()

{

   $exportData = [];

   try {

       $rawData = $this->collectRawData();

       $multirawData = $this->collectMultirawData();

       $productIds = array_keys($rawData);

       $stockItemRows = $this->prepareCatalogInventory($productIds);

       $this->rowCustomizer->prepareData(

           $this->_prepareEntityCollection($this->_entityCollectionFactory->create()),

           $productIds

       );

       $this->setHeaderColumns($multirawData[‘customOptionsData’], $stockItemRows);

       foreach ($rawData as $productId => $productData) {

           foreach ($productData as $storeId => $dataRow) {

               if ($storeId == Store::DEFAULT_STORE_ID && isset($stockItemRows[$productId])) {

                   $dataRow = array_merge($dataRow, $stockItemRows[$productId]);

               }

               $this->appendMultirowData($dataRow, $multirawData);

               if ($dataRow) {

                   $exportData[] = $dataRow;

               }

           }

       }

   } catch (\Exception $e) {   

       $this->_logger->critical($e);

   }

   return $exportData;

}

?>

The result is the absence of previously initialized column headers. The reason for the error is the absence of an element in the array that stores information about attribute sets. The product that will be exported to the file does not have a set, which in principle is not possible, since you create new products based on a specific attribute.

And if you open this product in the admin panel, then we get the following error.

1 exception(s):
Exception #0 (Magento\Framework\Exception\NoSuchEntityException): No such entity with attributeSetId = 67

The solution to the problem will be to find products that have incorrect attributes and replace them.

SQL script for searching for goods with sets that do not exist (10 is the type of the entity catalog_product)

SELECT * FROM catalog_product_entity AS e

LEFT JOIN eav_attribute_set AS a ON e.attribute_set_id=a.attribute_set_id AND a.entity_type_id=10

WHERE a.attribute_set_id IS NULL

Result

1521035819318

 

Example function – to set the default set of attributes for the products

<?php

namespace Sysint\CoreStore\Setup;

use Magento\Catalog\Model\ProductFactory;

class UpgradeData implements UpgradeDataInterface

{

   /**

    * @var ProductFactory

    */

   private $_productFactory;

   /**

    * Catalog config

    *

    * @var \Magento\Catalog\Model\Config

    */

   protected $_catalogConfig;

   /**

    * UpgradeData constructor.

    * @param ProductFactory $productFactory

    * @param \Magento\Catalog\Model\Config $catalogConfig

    */

   public function __construct(

       ProductFactory $productFactory,

       \Magento\Catalog\Model\Config $catalogConfig

   ) {

       $this->_productFactory = $productFactory;

       $this->_catalogConfig = $catalogConfig;

   }

   /**

    * Upgrades data for a module

    *

    * @param ModuleDataSetupInterface $setup

    * @param ModuleContextInterface $context

    * @return void

    */

   public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)

   {

       if (version_compare($context->getVersion(), ‘1.1.2’, ‘<‘)) {

           $this->fixAttributeSet($setup);

       }

   }

   private function fixAttributeSet(ModuleDataSetupInterface $setup){

       $productTable = $setup->getTable(‘catalog_product_entity’);

       $connection   = $setup->getConnection();

       $entityTypeId = $this->_catalogConfig->getEntityType(\Magento\Catalog\Model\Product::ENTITY)->getEntityTypeId();

       $select = $connection->select()

           ->from([‘e’ => $productTable], [‘entity_id’])

           ->joinLeft([‘a’ => $setup->getTable(‘eav_attribute_set’)],

               sprintf(‘e.attribute_set_id=a.attribute_set_id AND a.entity_type_id=%s’, $entityTypeId)

               , [])

           ->where(‘a.attribute_set_id IS NULL’)

       ;

       $ids = $connection->fetchCol($select);

       $setId = $this->_productFactory->create()->getDefaultAttributeSetId();

       if (is_array($ids) && count($ids) && is_numeric($setId)){

           $where = $connection->quoteInto(‘entity_id IN(?)’, $ids);

           $connection->update($productTable, [‘attribute_set_id’ => $setId], $where);

       }

   }

}