Возможно некоторые из вас, а я так точно столкнулся с проблемой, которая случилась во время экспорта товаров в CSV файл, а именно отсутствие половины информации для товаров, из 100 (условных) атрибутов выгрузились только 10 и случилось это после миграции данных Magento 1 Magento 2. Во время миграции не все наборы атрибутов из старого магазина в новый были перенесены, почему именно наборы и в каком то количестве, не могу сказать.
Как определить ошибку
- В файле экспорта есть не все колонки – атрибуты и их большое количество, но возможно в не которых случаях их меньше и соответственно это сложнее заметить
- В журнале ошибок exception.log есть ошибка ориентировочного такого содержания main.CRITICAL: Notice: Undefined offset: 1 in /vendor/magento/module-catalog-import-export/Model/Export/Product.php on line 1030
Функция в которой произошла ошибка и ее содержимое
<?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; } ?>
Если посмотреть на уровень выше – где вызывается эта функция, то в случае возникновения ошибки, инициализация заголовков для CVS файла обрывается
<?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; } ?>
Результат – отсутствие ранее инициализированных колонок – заголовков.
Причина ошибки – отсутствие элемента в массиве, который хранит информацию о наборах атрибутов. Товар который будет эскпортирован в файл не имеет набора, что в принципе не возможно, так как вы создаете новые товары на базе конкретного атрибута.
И если открыть этот товар в админ панели, то получим следующую ошибку.
1 exception(s): Exception #0 (Magento\Framework\Exception\NoSuchEntityException): No such entity with attributeSetId = 67
Решением проблемы будет поиск товаров, которые имеют не корректные атрибуты и их замена.
SQL скрипт для поиска товаров с наборами, которые не существуют (10 – это тип сущности 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
Результат
Пример функции – установка набора атрибутов по умолчанию для товаров
<?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); } } }

eCommerce/Magento Developer, PHP architect, based in Ukraine