/** * {@inheritdoc} */ public function isValid($value) { $this->_clearMessages(); if (!empty($value['_product_websites']) && !$this->storeResolver->getWebsiteCodeToId($value['_product_websites'])) { $this->_addMessages([self::ERROR_INVALID_WEBSITE]); return false; } return true; }
/** * Validate by website type * * @param array $value * @param string $websiteCode * @return bool */ protected function isWebsiteValid($value, $websiteCode) { if (isset($value[$websiteCode]) && !empty($value[$websiteCode])) { if ($value[$websiteCode] != $this->getAllWebsitesValue() && !$this->storeResolver->getWebsiteCodeToId($value[$websiteCode])) { return false; } } return true; }
/** * Validate value * * @param mixed $value * @return bool */ public function isValid($value) { $this->_clearMessages(); if ($value[AdvancedPricing::COL_TIER_PRICE_WEBSITE] != $this->getAllWebsitesValue() && $value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE] != $this->getAllWebsitesValue()) { if (!empty($value[AdvancedPricing::COL_TIER_PRICE_WEBSITE]) && !$this->storeResolver->getWebsiteCodeToId($value[AdvancedPricing::COL_TIER_PRICE_WEBSITE]) || !empty($value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE]) && !$this->storeResolver->getWebsiteCodeToId($value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE])) { $this->_addMessages([self::ERROR_INVALID_WEBSITE]); return false; } } return true; }
/** * {@inheritdoc} */ public function isValid($value) { $this->_clearMessages(); if (empty($value[ImportProduct::COL_PRODUCT_WEBSITES])) { return true; } $separator = $this->context->getMultipleValueSeparator(); $websites = explode($separator, $value[ImportProduct::COL_PRODUCT_WEBSITES]); foreach ($websites as $website) { if (!$this->storeResolver->getWebsiteCodeToId($website)) { $this->_addMessages([self::ERROR_INVALID_WEBSITE]); return false; } } return true; }
/** * {@inheritdoc} * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function isValid($value) { $this->_clearMessages(); if (isset($value['_group_price_website']) && strlen($value['_group_price_website']) || isset($value['_group_price_customer_group']) && strlen($value['_group_price_customer_group']) || isset($value['_group_price_price']) && strlen($value['_group_price_price'])) { if (!isset($value['_group_price_website']) || !isset($value['_group_price_customer_group']) || !strlen($value['_group_price_website']) || !strlen($value['_group_price_customer_group']) || !strlen($value['_group_price_price'])) { $this->_addMessages([self::ERROR_GROUP_PRICE_DATA_INCOMPLETE]); return false; } elseif ($value['_group_price_website'] != self::VALUE_ALL && !$this->storeResolver->getWebsiteCodeToId($value['_group_price_website'])) { $this->_addMessages([self::ERROR_INVALID_GROUP_PRICE_SITE]); return false; } elseif ($value['_group_price_customer_group'] != self::VALUE_ALL && !isset($this->customerGroups[$value['_group_price_customer_group']])) { $this->_addMessages([self::ERROR_INVALID_GROUP_PRICE_GROUP]); return false; } } return true; }
/** * 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; }
/** * Get website id by code * * @param string $websiteCode * @return array|int|string */ protected function getWebSiteId($websiteCode) { $result = $websiteCode == $this->_getValidator(self::VALIDATOR_WEBSITE)->getAllWebsitesValue() || $this->_catalogData->isPriceGlobal() ? 0 : $this->_storeResolver->getWebsiteCodeToId($websiteCode); return $result; }
/** * Gather and save information about product entities. * * @return $this * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function _saveProducts() { /** @var $resource \Magento\CatalogImportExport\Model\Import\Proxy\Product\Resource */ $resource = $this->_resourceFactory->create(); $priceIsGlobal = $this->_catalogData->isPriceGlobal(); $productLimit = null; $productsQty = null; while ($bunch = $this->_dataSourceModel->getNextBunch()) { $entityRowsIn = []; $entityRowsUp = []; $attributes = []; $websites = []; $categories = []; $tierPrices = []; $groupPrices = []; $mediaGallery = []; $uploadedGalleryFiles = []; $previousType = null; $prevAttributeSet = null; foreach ($bunch as $rowNum => $rowData) { if (!$this->validateRow($rowData, $rowNum)) { continue; } $rowScope = $this->getRowScope($rowData); if (self::SCOPE_DEFAULT == $rowScope) { $rowSku = $rowData[self::COL_SKU]; // 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 { // new row 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->_rowsToSkip[$rowNum] = true; continue; } } } elseif (null === $rowSku) { $this->_rowsToSkip[$rowNum] = true; // skip rows when SKU is NULL 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']; } // 2. Product-to-Website phase if (!empty($rowData['_product_websites'])) { $websites[$rowSku][$this->storeResolver->getWebsiteCodeToId($rowData['_product_websites'])] = true; } // 3. Categories phase $categoryPath = empty($rowData[self::COL_CATEGORY]) ? '' : $rowData[self::COL_CATEGORY]; if (!empty($rowData[self::COL_ROOT_CATEGORY])) { $categoryId = $this->categoryProcessor->getCategoryWithRoot($rowData[self::COL_ROOT_CATEGORY], $categoryPath); $categories[$rowSku][$categoryId] = true; } elseif (!empty($categoryPath)) { $categories[$rowSku][$this->categoryProcessor->getCategory($categoryPath)] = 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'])]; } // 4.2. Group prices phase if (!empty($rowData['_group_price_website'])) { $groupPrices[$rowSku][] = ['all_groups' => $rowData['_group_price_customer_group'] == self::VALUE_ALL, 'customer_group_id' => $rowData['_group_price_customer_group'] == self::VALUE_ALL ? 0 : $rowData['_group_price_customer_group'], 'value' => $rowData['_group_price_price'], 'website_id' => self::VALUE_ALL == $rowData['_group_price_website'] || $priceIsGlobal ? 0 : $this->storeResolver->getWebsiteCodeToId($rowData['_group_price_website'])]; } // 5. Media gallery phase foreach ($this->_imagesArrayKeys as $imageCol) { if (!empty($rowData[$imageCol])) { if (!array_key_exists($rowData[$imageCol], $uploadedGalleryFiles)) { $uploadedGalleryFiles[$rowData[$imageCol]] = $this->_uploadMediaFiles($rowData[$imageCol]); } $rowData[$imageCol] = $uploadedGalleryFiles[$rowData[$imageCol]]; } } if (!empty($rowData['_media_image'])) { $mediaGallery[$rowSku][] = ['attribute_id' => $rowData['_media_attribute_id'], 'label' => $rowData['_media_label'], 'position' => $rowData['_media_position'], 'disabled' => $rowData['_media_is_disabled'], 'value' => $rowData['_media_image']]; } // 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; } } if ($this->getBehavior() == \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND || empty($rowData[self::COL_SKU])) { $rowData = $this->_productTypeModels[$productType]->clearEmptyData($rowData); } $rowData = $this->_productTypeModels[$productType]->prepareAttributesWithDefaultValueForSave($rowData, !isset($this->_oldSku[$rowSku])); $product = $this->_proxyProdFactory->create(['data' => $rowData]); foreach ($rowData as $attrCode => $attrValue) { $attribute = $resource->getAttribute($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]; } } foreach ($storeIds as $storeId) { if ('multiselect' == $attribute->getFrontendInput()) { if (!isset($attributes[$attrTable][$rowSku][$attrId][$storeId])) { $attributes[$attrTable][$rowSku][$attrId][$storeId] = ''; } else { $attributes[$attrTable][$rowSku][$attrId][$storeId] .= ','; } $attributes[$attrTable][$rowSku][$attrId][$storeId] .= $attrValue; } else { $attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue; } } // restore 'backend_model' to avoid 'default' setting $attribute->setBackendModel($backModel); } } $this->_saveProductEntity($entityRowsIn, $entityRowsUp)->_saveProductWebsites($websites)->_saveProductCategories($categories)->_saveProductTierPrices($tierPrices)->_saveProductGroupPrices($groupPrices)->_saveMediaGallery($mediaGallery)->_saveProductAttributes($attributes); } return $this; }