33 * Copyright © Magento, Inc. All rights reserved.
44 * See COPYING.txt for license details.
55 */
6+
67namespace Magento \CatalogImportExport \Model \Import ;
78
89use Magento \Catalog \Api \ProductRepositoryInterface ;
910use Magento \Catalog \Model \Config as CatalogConfig ;
1011use Magento \Catalog \Model \Product \Visibility ;
11- use Magento \CatalogImportExport \Model \Import \Product \MediaGalleryProcessor ;
1212use Magento \CatalogImportExport \Model \Import \Product \ImageTypeProcessor ;
13+ use Magento \CatalogImportExport \Model \Import \Product \MediaGalleryProcessor ;
1314use Magento \CatalogImportExport \Model \Import \Product \RowValidatorInterface as ValidatorInterface ;
14- use Magento \CatalogInventory \Api \Data \StockItemInterface ;
1515use Magento \CatalogImportExport \Model \StockItemImporterInterface ;
16+ use Magento \CatalogInventory \Api \Data \StockItemInterface ;
1617use Magento \Framework \App \Filesystem \DirectoryList ;
1718use Magento \Framework \App \ObjectManager ;
1819use Magento \Framework \Exception \LocalizedException ;
@@ -307,7 +308,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
307308 ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE => 'Imported resource (image) could not be downloaded from external resource due to timeout or access permissions ' ,
308309 ValidatorInterface::ERROR_INVALID_WEIGHT => 'Product weight is invalid ' ,
309310 ValidatorInterface::ERROR_DUPLICATE_URL_KEY => 'Url key: \'%s \' was already generated for an item with the SKU: \'%s \'. You need to specify the unique URL key manually ' ,
310- ValidatorInterface::ERROR_DUPLICATE_MULTISELECT_VALUES => " Value for multiselect attribute %s contains duplicated values " ,
311+ ValidatorInterface::ERROR_DUPLICATE_MULTISELECT_VALUES => ' Value for multiselect attribute %s contains duplicated values ' ,
311312 ValidatorInterface::ERROR_NEW_TO_DATE => 'Make sure new_to_date is later than or the same as new_from_date ' ,
312313 ];
313314 //@codingStandardsIgnoreEnd
@@ -795,6 +796,8 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
795796 * @param StockItemImporterInterface|null $stockItemImporter
796797 * @param DateTimeFactory $dateTimeFactory
797798 * @param ProductRepositoryInterface|null $productRepository
799+ * @throws LocalizedException
800+ * @throws \Magento\Framework\Exception\FileSystemException
798801 * @SuppressWarnings(PHPMD.ExcessiveParameterList)
799802 * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
800803 */
@@ -913,7 +916,7 @@ public function isAttributeValid($attrCode, array $attrParams, array $rowData, $
913916 {
914917 if (!$ this ->validator ->isAttributeValid ($ attrCode , $ attrParams , $ rowData )) {
915918 foreach ($ this ->validator ->getMessages () as $ message ) {
916- $ this ->addRowError ( $ message , $ rowNum , $ attrCode );
919+ $ this ->skipRow ( $ rowNum , $ message , ProcessingError:: ERROR_LEVEL_NOT_CRITICAL , $ attrCode );
917920 }
918921 return false ;
919922 }
@@ -1646,19 +1649,16 @@ protected function _saveProducts()
16461649 continue ;
16471650 }
16481651 if ($ this ->getErrorAggregator ()->hasToBeTerminated ()) {
1649- $ validationStrategy = $ this ->_parameters [Import::FIELD_NAME_VALIDATION_STRATEGY ];
1650- if (ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS !== $ validationStrategy ) {
1651- $ this ->getErrorAggregator ()->addRowToSkip ($ rowNum );
1652- continue ;
1653- }
1652+ $ this ->getErrorAggregator ()->addRowToSkip ($ rowNum );
1653+ continue ;
16541654 }
16551655 $ rowScope = $ this ->getRowScope ($ rowData );
16561656
16571657 $ urlKey = $ this ->getUrlKey ($ rowData );
16581658 if (!empty ($ rowData [self ::URL_KEY ])) {
16591659 // If url_key column and its value were in the CSV file
16601660 $ rowData [self ::URL_KEY ] = $ urlKey ;
1661- } else if ($ this ->isNeedToChangeUrlKey ($ rowData )) {
1661+ } elseif ($ this ->isNeedToChangeUrlKey ($ rowData )) {
16621662 // If url_key column was empty or even not declared in the CSV file but by the rules it is need to
16631663 // be setteed. In case when url_key is generating from name column we have to ensure that the bunch
16641664 // of products will pass for the event with url_key column.
@@ -1670,7 +1670,9 @@ protected function _saveProducts()
16701670 if (null === $ rowSku ) {
16711671 $ this ->getErrorAggregator ()->addRowToSkip ($ rowNum );
16721672 continue ;
1673- } elseif (self ::SCOPE_STORE == $ rowScope ) {
1673+ }
1674+
1675+ if (self ::SCOPE_STORE == $ rowScope ) {
16741676 // set necessary data from SCOPE_DEFAULT row
16751677 $ rowData [self ::COL_TYPE ] = $ this ->skuProcessor ->getNewSku ($ rowSku )['type_id ' ];
16761678 $ rowData ['attribute_set_id ' ] = $ this ->skuProcessor ->getNewSku ($ rowSku )['attr_set_id ' ];
@@ -1806,13 +1808,7 @@ protected function _saveProducts()
18061808 $ uploadedImages [$ columnImage ] = $ uploadedFile ;
18071809 } else {
18081810 unset($ rowData [$ column ]);
1809- $ this ->addRowError (
1810- ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE ,
1811- $ rowNum ,
1812- null ,
1813- null ,
1814- ProcessingError::ERROR_LEVEL_NOT_CRITICAL
1815- );
1811+ $ this ->skipRow ($ rowNum , ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE );
18161812 }
18171813 } else {
18181814 $ uploadedFile = $ uploadedImages [$ columnImage ];
@@ -2436,6 +2432,7 @@ public function getRowScope(array $rowData)
24362432 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
24372433 * @SuppressWarnings(PHPMD.NPathComplexity)
24382434 * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
2435+ * @throws \Zend_Validate_Exception
24392436 */
24402437 public function validateRow (array $ rowData , $ rowNum )
24412438 {
@@ -2451,32 +2448,35 @@ public function validateRow(array $rowData, $rowNum)
24512448 // BEHAVIOR_DELETE and BEHAVIOR_REPLACE use specific validation logic
24522449 if (Import::BEHAVIOR_REPLACE == $ this ->getBehavior ()) {
24532450 if (self ::SCOPE_DEFAULT == $ rowScope && !$ this ->isSkuExist ($ sku )) {
2454- $ this ->addRowError ( ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE , $ rowNum );
2451+ $ this ->skipRow ( $ rowNum , ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE );
24552452 return false ;
24562453 }
24572454 }
24582455 if (Import::BEHAVIOR_DELETE == $ this ->getBehavior ()) {
24592456 if (self ::SCOPE_DEFAULT == $ rowScope && !$ this ->isSkuExist ($ sku )) {
2460- $ this ->addRowError ( ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE , $ rowNum );
2457+ $ this ->skipRow ( $ rowNum , ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE );
24612458 return false ;
24622459 }
24632460 return true ;
24642461 }
24652462
2463+ // if product doesn't exist, need to throw critical error else all errors should be not critical.
2464+ $ errorLevel = $ this ->getValidationErrorLevel ($ sku );
2465+
24662466 if (!$ this ->validator ->isValid ($ rowData )) {
24672467 foreach ($ this ->validator ->getMessages () as $ message ) {
2468- $ this ->addRowError ( $ message , $ rowNum , $ this ->validator ->getInvalidAttribute ());
2468+ $ this ->skipRow ( $ rowNum , $ message , $ errorLevel , $ this ->validator ->getInvalidAttribute ());
24692469 }
24702470 }
24712471
24722472 if (null === $ sku ) {
2473- $ this ->addRowError ( ValidatorInterface::ERROR_SKU_IS_EMPTY , $ rowNum );
2473+ $ this ->skipRow ( $ rowNum , ValidatorInterface::ERROR_SKU_IS_EMPTY , $ errorLevel );
24742474 } elseif (false === $ sku ) {
2475- $ this ->addRowError ( ValidatorInterface::ERROR_ROW_IS_ORPHAN , $ rowNum );
2475+ $ this ->skipRow ( $ rowNum , ValidatorInterface::ERROR_ROW_IS_ORPHAN , $ errorLevel );
24762476 } elseif (self ::SCOPE_STORE == $ rowScope
24772477 && !$ this ->storeResolver ->getStoreCodeToId ($ rowData [self ::COL_STORE ])
24782478 ) {
2479- $ this ->addRowError ( ValidatorInterface::ERROR_INVALID_STORE , $ rowNum );
2479+ $ this ->skipRow ( $ rowNum , ValidatorInterface::ERROR_INVALID_STORE , $ errorLevel );
24802480 }
24812481
24822482 // SKU is specified, row is SCOPE_DEFAULT, new product block begins
@@ -2491,16 +2491,15 @@ public function validateRow(array $rowData, $rowNum)
24912491 $ this ->prepareNewSkuData ($ sku )
24922492 );
24932493 } else {
2494- $ this ->addRowError ( ValidatorInterface::ERROR_TYPE_UNSUPPORTED , $ rowNum );
2494+ $ this ->skipRow ( $ rowNum , ValidatorInterface::ERROR_TYPE_UNSUPPORTED , $ errorLevel );
24952495 }
24962496 } else {
24972497 // validate new product type and attribute set
2498- if (!isset ($ rowData [self ::COL_TYPE ]) || !isset ($ this ->_productTypeModels [$ rowData [self ::COL_TYPE ]])) {
2499- $ this ->addRowError (ValidatorInterface::ERROR_INVALID_TYPE , $ rowNum );
2500- } elseif (!isset ($ rowData [self ::COL_ATTR_SET ])
2501- || !isset ($ this ->_attrSetNameToId [$ rowData [self ::COL_ATTR_SET ]])
2498+ if (!isset ($ rowData [self ::COL_TYPE ], $ this ->_productTypeModels [$ rowData [self ::COL_TYPE ]])) {
2499+ $ this ->skipRow ($ rowNum , ValidatorInterface::ERROR_INVALID_TYPE , $ errorLevel );
2500+ } elseif (!isset ($ rowData [self ::COL_ATTR_SET ], $ this ->_attrSetNameToId [$ rowData [self ::COL_ATTR_SET ]])
25022501 ) {
2503- $ this ->addRowError ( ValidatorInterface::ERROR_INVALID_ATTR_SET , $ rowNum );
2502+ $ this ->skipRow ( $ rowNum , ValidatorInterface::ERROR_INVALID_ATTR_SET , $ errorLevel );
25042503 } elseif ($ this ->skuProcessor ->getNewSku ($ sku ) === null ) {
25052504 $ this ->skuProcessor ->addNewSku (
25062505 $ sku ,
@@ -2556,8 +2555,11 @@ public function validateRow(array $rowData, $rowNum)
25562555 ValidatorInterface::ERROR_DUPLICATE_URL_KEY ,
25572556 $ rowNum ,
25582557 $ rowData [self ::COL_NAME ],
2559- $ message
2560- );
2558+ $ message ,
2559+ ProcessingError::ERROR_LEVEL_NOT_CRITICAL
2560+ )
2561+ ->getErrorAggregator ()
2562+ ->addRowToSkip ($ rowNum );
25612563 }
25622564 }
25632565 }
@@ -2567,9 +2569,10 @@ public function validateRow(array $rowData, $rowNum)
25672569 $ newFromTimestamp = strtotime ($ this ->dateTime ->formatDate ($ rowData [self ::COL_NEW_FROM_DATE ], false ));
25682570 $ newToTimestamp = strtotime ($ this ->dateTime ->formatDate ($ rowData [self ::COL_NEW_TO_DATE ], false ));
25692571 if ($ newFromTimestamp > $ newToTimestamp ) {
2570- $ this ->addRowError (
2571- ValidatorInterface::ERROR_NEW_TO_DATE ,
2572+ $ this ->skipRow (
25722573 $ rowNum ,
2574+ ValidatorInterface::ERROR_NEW_TO_DATE ,
2575+ $ errorLevel ,
25732576 $ rowData [self ::COL_NEW_TO_DATE ]
25742577 );
25752578 }
@@ -2588,8 +2591,8 @@ private function isNeedToValidateUrlKey($rowData)
25882591 {
25892592 return (!empty ($ rowData [self ::URL_KEY ]) || !empty ($ rowData [self ::COL_NAME ]))
25902593 && (empty ($ rowData [self ::COL_VISIBILITY ])
2591- || $ rowData [self ::COL_VISIBILITY ]
2592- !== (string )Visibility::getOptionArray ()[Visibility::VISIBILITY_NOT_VISIBLE ]);
2594+ || $ rowData [self ::COL_VISIBILITY ]
2595+ !== (string )Visibility::getOptionArray ()[Visibility::VISIBILITY_NOT_VISIBLE ]);
25932596 }
25942597
25952598 /**
@@ -3095,4 +3098,38 @@ private function retrieveProductBySku($sku)
30953098 }
30963099 return $ product ;
30973100 }
3101+
3102+ /**
3103+ * Add row as skipped
3104+ *
3105+ * @param int $rowNum
3106+ * @param string $errorCode Error code or simply column name
3107+ * @param string $errorLevel error level
3108+ * @param string|null $colName optional column name
3109+ * @return $this
3110+ */
3111+ private function skipRow (
3112+ $ rowNum ,
3113+ string $ errorCode ,
3114+ string $ errorLevel = ProcessingError::ERROR_LEVEL_NOT_CRITICAL ,
3115+ $ colName = null
3116+ ): self {
3117+ $ this ->addRowError ($ errorCode , $ rowNum , $ colName , null , $ errorLevel );
3118+ $ this ->getErrorAggregator ()
3119+ ->addRowToSkip ($ rowNum );
3120+ return $ this ;
3121+ }
3122+
3123+ /**
3124+ * Returns errorLevel for validation
3125+ *
3126+ * @param string $sku
3127+ * @return string
3128+ */
3129+ private function getValidationErrorLevel ($ sku ): string
3130+ {
3131+ return (!$ this ->isSkuExist ($ sku ) && Import::BEHAVIOR_REPLACE !== $ this ->getBehavior ())
3132+ ? ProcessingError::ERROR_LEVEL_CRITICAL
3133+ : ProcessingError::ERROR_LEVEL_NOT_CRITICAL ;
3134+ }
30983135}
0 commit comments