Skip to content

Commit 02b5ff6

Browse files
committed
Merge remote-tracking branch 'origin/2.3-develop' into 2.3-develop-mftf-pr12
2 parents 782d0c9 + da1173a commit 02b5ff6

File tree

8 files changed

+270
-165
lines changed

8 files changed

+270
-165
lines changed

app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ protected function duplicate($product)
318318

319319
$this->resourceModel->duplicate(
320320
$this->getAttribute()->getAttributeId(),
321-
isset($mediaGalleryData['duplicate']) ? $mediaGalleryData['duplicate'] : [],
321+
$mediaGalleryData['duplicate'] ?? [],
322322
$product->getOriginalLinkId(),
323323
$product->getData($this->metadata->getLinkField())
324324
);

app/code/Magento/Catalog/Model/ResourceModel/Product/Gallery.php

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Catalog\Model\ResourceModel\Product;
78

89
use Magento\Store\Model\Store;
@@ -149,7 +150,7 @@ public function loadProductGalleryByAttributeId($product, $attributeId)
149150
*/
150151
protected function createBaseLoadSelect($entityId, $storeId, $attributeId)
151152
{
152-
$select = $this->createBatchBaseSelect($storeId, $attributeId);
153+
$select = $this->createBatchBaseSelect($storeId, $attributeId);
153154

154155
$select = $select->where(
155156
'entity.' . $this->metadata->getLinkField() . ' = ?',
@@ -378,9 +379,9 @@ public function deleteGalleryValueInStore($valueId, $entityId, $storeId)
378379
$conditions = implode(
379380
' AND ',
380381
[
381-
$this->getConnection()->quoteInto('value_id = ?', (int) $valueId),
382-
$this->getConnection()->quoteInto($this->metadata->getLinkField() . ' = ?', (int) $entityId),
383-
$this->getConnection()->quoteInto('store_id = ?', (int) $storeId)
382+
$this->getConnection()->quoteInto('value_id = ?', (int)$valueId),
383+
$this->getConnection()->quoteInto($this->metadata->getLinkField() . ' = ?', (int)$entityId),
384+
$this->getConnection()->quoteInto('store_id = ?', (int)$storeId)
384385
]
385386
);
386387

@@ -408,7 +409,7 @@ public function duplicate($attributeId, $newFiles, $originalProductId, $newProdu
408409

409410
$select = $this->getConnection()->select()->from(
410411
[$this->getMainTableAlias() => $this->getMainTable()],
411-
['value_id', 'value']
412+
['value_id', 'value', 'media_type', 'disabled']
412413
)->joinInner(
413414
['entity' => $this->getTable(self::GALLERY_VALUE_TO_ENTITY_TABLE)],
414415
$this->getMainTableAlias() . '.value_id = entity.value_id',
@@ -425,16 +426,16 @@ public function duplicate($attributeId, $newFiles, $originalProductId, $newProdu
425426

426427
// Duplicate main entries of gallery
427428
foreach ($this->getConnection()->fetchAll($select) as $row) {
428-
$data = [
429-
'attribute_id' => $attributeId,
430-
'value' => isset($newFiles[$row['value_id']]) ? $newFiles[$row['value_id']] : $row['value'],
431-
];
429+
$data = $row;
430+
$data['attribute_id'] = $attributeId;
431+
$data['value'] = $newFiles[$row['value_id']] ?? $row['value'];
432+
unset($data['value_id']);
432433

433434
$valueIdMap[$row['value_id']] = $this->insertGallery($data);
434435
$this->bindValueToEntity($valueIdMap[$row['value_id']], $newProductId);
435436
}
436437

437-
if (count($valueIdMap) == 0) {
438+
if (count($valueIdMap) === 0) {
438439
return [];
439440
}
440441

app/code/Magento/CatalogImportExport/Model/Import/Product.php

Lines changed: 73 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\CatalogImportExport\Model\Import;
78

89
use Magento\Catalog\Api\ProductRepositoryInterface;
910
use Magento\Catalog\Model\Config as CatalogConfig;
1011
use Magento\Catalog\Model\Product\Visibility;
11-
use Magento\CatalogImportExport\Model\Import\Product\MediaGalleryProcessor;
1212
use Magento\CatalogImportExport\Model\Import\Product\ImageTypeProcessor;
13+
use Magento\CatalogImportExport\Model\Import\Product\MediaGalleryProcessor;
1314
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as ValidatorInterface;
14-
use Magento\CatalogInventory\Api\Data\StockItemInterface;
1515
use Magento\CatalogImportExport\Model\StockItemImporterInterface;
16+
use Magento\CatalogInventory\Api\Data\StockItemInterface;
1617
use Magento\Framework\App\Filesystem\DirectoryList;
1718
use Magento\Framework\App\ObjectManager;
1819
use 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

Comments
 (0)