Example #1
0
 /**
  * Gather and save information about product entities.
  *
  * @return $this
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @SuppressWarnings(PHPMD.NPathComplexity)
  * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  * @SuppressWarnings(PHPMD.UnusedLocalVariable)
  */
 protected function _saveProducts()
 {
     /** @var $resource \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel */
     $resource = $this->_resourceFactory->create();
     $priceIsGlobal = $this->_catalogData->isPriceGlobal();
     $productLimit = null;
     $productsQty = null;
     while ($bunch = $this->_dataSourceModel->getNextBunch()) {
         $entityRowsIn = [];
         $entityRowsUp = [];
         $attributes = [];
         $this->websitesCache = [];
         $this->categoriesCache = [];
         $tierPrices = [];
         $mediaGallery = [];
         $uploadedGalleryFiles = [];
         $previousType = null;
         $prevAttributeSet = null;
         $allImagesFromBunch = $this->_getAllBunchImages($bunch);
         $existingImages = $this->_prepareAllMediaFiles($allImagesFromBunch);
         foreach ($bunch as $rowNum => $rowData) {
             if (!$this->validateRow($rowData, $rowNum)) {
                 continue;
             }
             if ($this->getErrorAggregator()->hasToBeTerminated()) {
                 $this->getErrorAggregator()->addRowToSkip($rowNum);
                 continue;
             }
             $rowScope = $this->getRowScope($rowData);
             $rowSku = $rowData[self::COL_SKU];
             if (null === $rowSku) {
                 $this->getErrorAggregator()->addRowToSkip($rowNum);
                 continue;
             } elseif (self::SCOPE_STORE == $rowScope) {
                 // set necessary data from SCOPE_DEFAULT row
                 $rowData[self::COL_TYPE] = $this->skuProcessor->getNewSku($rowSku)['type_id'];
                 $rowData['attribute_set_id'] = $this->skuProcessor->getNewSku($rowSku)['attr_set_id'];
                 $rowData[self::COL_ATTR_SET] = $this->skuProcessor->getNewSku($rowSku)['attr_set_code'];
             }
             // 1. Entity phase
             if (isset($this->_oldSku[$rowSku])) {
                 // existing row
                 $entityRowsUp[] = ['updated_at' => (new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT), 'entity_id' => $this->_oldSku[$rowSku]['entity_id']];
             } else {
                 if (!$productLimit || $productsQty < $productLimit) {
                     $entityRowsIn[$rowSku] = ['attribute_set_id' => $this->skuProcessor->getNewSku($rowSku)['attr_set_id'], 'type_id' => $this->skuProcessor->getNewSku($rowSku)['type_id'], 'sku' => $rowSku, 'has_options' => isset($rowData['has_options']) ? $rowData['has_options'] : 0, 'created_at' => (new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT), 'updated_at' => (new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT)];
                     $productsQty++;
                 } else {
                     $rowSku = null;
                     // sign for child rows to be skipped
                     $this->getErrorAggregator()->addRowToSkip($rowNum);
                     continue;
                 }
             }
             $this->websitesCache[$rowSku] = [];
             // 2. Product-to-Website phase
             if (!empty($rowData[self::COL_PRODUCT_WEBSITES])) {
                 $websiteCodes = explode($this->getMultipleValueSeparator(), $rowData[self::COL_PRODUCT_WEBSITES]);
                 foreach ($websiteCodes as $websiteCode) {
                     $websiteId = $this->storeResolver->getWebsiteCodeToId($websiteCode);
                     $this->websitesCache[$rowSku][$websiteId] = true;
                 }
             }
             // 3. Categories phase
             $categoriesString = empty($rowData[self::COL_CATEGORY]) ? '' : $rowData[self::COL_CATEGORY];
             $this->categoriesCache[$rowSku] = [];
             if (!empty($categoriesString)) {
                 foreach ($this->categoryProcessor->upsertCategories($categoriesString) as $categoryId) {
                     $this->categoriesCache[$rowSku][$categoryId] = true;
                 }
             }
             // 4.1. Tier prices phase
             if (!empty($rowData['_tier_price_website'])) {
                 $tierPrices[$rowSku][] = ['all_groups' => $rowData['_tier_price_customer_group'] == self::VALUE_ALL, 'customer_group_id' => $rowData['_tier_price_customer_group'] == self::VALUE_ALL ? 0 : $rowData['_tier_price_customer_group'], 'qty' => $rowData['_tier_price_qty'], 'value' => $rowData['_tier_price_price'], 'website_id' => self::VALUE_ALL == $rowData['_tier_price_website'] || $priceIsGlobal ? 0 : $this->storeResolver->getWebsiteCodeToId($rowData['_tier_price_website'])];
             }
             if (!$this->validateRow($rowData, $rowNum)) {
                 continue;
             }
             // 5. Media gallery phase
             $mediaGalleryImages = array();
             $mediaGalleryLabels = array();
             if (!empty($rowData[self::COL_MEDIA_IMAGE])) {
                 $mediaGalleryImages = explode($this->getMultipleValueSeparator(), $rowData[self::COL_MEDIA_IMAGE]);
                 if (isset($rowData['_media_image_label'])) {
                     $mediaGalleryLabels = explode($this->getMultipleValueSeparator(), $rowData['_media_image_label']);
                 } else {
                     $mediaGalleryLabels = [];
                 }
                 if (count($mediaGalleryLabels) > count($mediaGalleryImages)) {
                     $mediaGalleryLabels = array_slice($mediaGalleryLabels, 0, count($mediaGalleryImages));
                 } elseif (count($mediaGalleryLabels) < count($mediaGalleryImages)) {
                     $mediaGalleryLabels = array_pad($mediaGalleryLabels, count($mediaGalleryImages), '');
                 }
             }
             foreach ($this->_imagesArrayKeys as $imageCol) {
                 if (!empty($rowData[$imageCol]) && $imageCol != self::COL_MEDIA_IMAGE && !in_array($rowData[$imageCol], $mediaGalleryImages)) {
                     $mediaGalleryImages[] = $rowData[$imageCol];
                     if (isset($mediaGalleryLabels)) {
                         $mediaGalleryLabels[] = isset($rowData[$imageCol . '_label']) ? $rowData[$imageCol . '_label'] : '';
                     } else {
                         $mediaGalleryLabels[] = '';
                     }
                 }
             }
             $rowData[self::COL_MEDIA_IMAGE] = array();
             foreach ($mediaGalleryImages as $mediaImage) {
                 $imagePath = $allImagesFromBunch[$mediaImage];
                 if (isset($existingImages[$imagePath]) && in_array($rowSku, $existingImages[$imagePath])) {
                     if (!array_key_exists($mediaImage, $uploadedGalleryFiles)) {
                         $uploadedFile = $this->_uploadMediaFiles(trim($mediaImage), true);
                         if ($uploadedFile) {
                             $uploadedGalleryFiles[$mediaImage] = $uploadedFile;
                         } else {
                             $this->addRowError(ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, null, null, ProcessingError::ERROR_LEVEL_NOT_CRITICAL);
                         }
                     }
                 } elseif (!isset($existingImages[$imagePath])) {
                     if (!array_key_exists($mediaImage, $uploadedGalleryFiles)) {
                         $uploadedFile = $this->_uploadMediaFiles(trim($mediaImage), true);
                         if ($uploadedFile) {
                             $uploadedGalleryFiles[$mediaImage] = $uploadedFile;
                             $newImagePath = $uploadedGalleryFiles[$mediaImage];
                             $existingImages[$newImagePath][] = $rowSku;
                         } else {
                             $this->addRowError(ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, null, null, ProcessingError::ERROR_LEVEL_NOT_CRITICAL);
                         }
                     }
                     if (isset($uploadedGalleryFiles[$mediaImage])) {
                         $rowData[self::COL_MEDIA_IMAGE][] = $uploadedGalleryFiles[$mediaImage];
                         if (!empty($rowData[self::COL_MEDIA_IMAGE]) && is_array($rowData[self::COL_MEDIA_IMAGE])) {
                             $position = array_search($mediaImage, $mediaGalleryImages);
                             foreach ($rowData[self::COL_MEDIA_IMAGE] as $mediaImage) {
                                 $mediaGallery[$rowSku][] = ['attribute_id' => $this->getMediaGalleryAttributeId(), 'label' => isset($mediaGalleryLabels[$position]) ? $mediaGalleryLabels[$position] : '', 'position' => $position, 'disabled' => '', 'value' => $mediaImage];
                             }
                         }
                     }
                 }
                 foreach ($this->_imagesArrayKeys as $imageCol) {
                     if (empty($rowData[$imageCol]) || $imageCol == self::COL_MEDIA_IMAGE) {
                         continue;
                     }
                     if (isset($existingImages[$imagePath]) && !in_array($rowSku, $existingImages[$imagePath]) && ($rowData[$imageCol] == $imagePath || $rowData[$imageCol] == $mediaImage)) {
                         unset($rowData[$imageCol]);
                     } elseif (isset($uploadedGalleryFiles[$rowData[$imageCol]])) {
                         $rowData[$imageCol] = $uploadedGalleryFiles[$rowData[$imageCol]];
                     }
                 }
             }
             // 6. Attributes phase
             $rowStore = self::SCOPE_STORE == $rowScope ? $this->storeResolver->getStoreCodeToId($rowData[self::COL_STORE]) : 0;
             $productType = isset($rowData[self::COL_TYPE]) ? $rowData[self::COL_TYPE] : null;
             if (!is_null($productType)) {
                 $previousType = $productType;
             }
             if (isset($rowData[self::COL_ATTR_SET])) {
                 $prevAttributeSet = $rowData[self::COL_ATTR_SET];
             }
             if (self::SCOPE_NULL == $rowScope) {
                 // for multiselect attributes only
                 if (!is_null($prevAttributeSet)) {
                     $rowData[self::COL_ATTR_SET] = $prevAttributeSet;
                 }
                 if (is_null($productType) && !is_null($previousType)) {
                     $productType = $previousType;
                 }
                 if (is_null($productType)) {
                     continue;
                 }
             }
             $productTypeModel = $this->_productTypeModels[$productType];
             if (!empty($rowData['tax_class_name'])) {
                 $rowData['tax_class_id'] = $this->taxClassProcessor->upsertTaxClass($rowData['tax_class_name'], $productTypeModel);
             }
             if ($this->getBehavior() == \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND || empty($rowData[self::COL_SKU])) {
                 $rowData = $productTypeModel->clearEmptyData($rowData);
             }
             $rowData = $productTypeModel->prepareAttributesWithDefaultValueForSave($rowData, !isset($this->_oldSku[$rowSku]));
             $product = $this->_proxyProdFactory->create(['data' => $rowData]);
             foreach ($rowData as $attrCode => $attrValue) {
                 $attribute = $this->retrieveAttributeByCode($attrCode);
                 if ('multiselect' != $attribute->getFrontendInput() && self::SCOPE_NULL == $rowScope) {
                     // skip attribute processing for SCOPE_NULL rows
                     continue;
                 }
                 $attrId = $attribute->getId();
                 $backModel = $attribute->getBackendModel();
                 $attrTable = $attribute->getBackend()->getTable();
                 $storeIds = [0];
                 if ('datetime' == $attribute->getBackendType() && strtotime($attrValue)) {
                     $attrValue = (new \DateTime())->setTimestamp(strtotime($attrValue));
                     $attrValue = $attrValue->format(DateTime::DATETIME_PHP_FORMAT);
                 } elseif ($backModel) {
                     $attribute->getBackend()->beforeSave($product);
                     $attrValue = $product->getData($attribute->getAttributeCode());
                 }
                 if (self::SCOPE_STORE == $rowScope) {
                     if (self::SCOPE_WEBSITE == $attribute->getIsGlobal()) {
                         // check website defaults already set
                         if (!isset($attributes[$attrTable][$rowSku][$attrId][$rowStore])) {
                             $storeIds = $this->storeResolver->getStoreIdToWebsiteStoreIds($rowStore);
                         }
                     } elseif (self::SCOPE_STORE == $attribute->getIsGlobal()) {
                         $storeIds = [$rowStore];
                     }
                     if (!isset($this->_oldSku[$rowSku])) {
                         $storeIds[] = 0;
                     }
                 }
                 foreach ($storeIds as $storeId) {
                     $attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue;
                 }
                 // restore 'backend_model' to avoid 'default' setting
                 $attribute->setBackendModel($backModel);
             }
         }
         $this->_saveProductEntity($entityRowsIn, $entityRowsUp)->_saveProductWebsites($this->websitesCache)->_saveProductCategories($this->categoriesCache)->_saveProductTierPrices($tierPrices)->_saveMediaGallery($mediaGallery)->_saveProductAttributes($attributes);
         $this->_eventManager->dispatch('catalog_product_import_bunch_save_after', ['adapter' => $this, 'bunch' => $bunch]);
     }
     return $this;
 }
 public function testUpsertTaxClassNotExist()
 {
     $taxClassId = $this->taxClassProcessor->upsertTaxClass('noExistClassName', $this->product);
     $this->assertEquals(self::TEST_JUST_CREATED_TAX_CLASS_ID, $taxClassId);
 }