Skip to content

Commit fe6d86e

Browse files
committed
Merge remote-tracking branch 'mainline/2.4-develop' into ACP2E-1930
Conflicts: app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
2 parents 002b09d + 4b45119 commit fe6d86e

File tree

28 files changed

+1501
-320
lines changed

28 files changed

+1501
-320
lines changed

app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,26 @@ protected function parseSelections($rowData, $entityId)
181181
return [];
182182
}
183183

184-
$rowData['bundle_values'] = str_replace(
185-
self::BEFORE_OPTION_VALUE_DELIMITER,
186-
$this->_entityModel->getMultipleValueSeparator(),
187-
$rowData['bundle_values']
188-
);
189-
$selections = explode(
190-
Product::PSEUDO_MULTI_LINE_SEPARATOR,
191-
$rowData['bundle_values']
192-
);
184+
if (is_string($rowData['bundle_values'])) {
185+
$rowData['bundle_values'] = str_replace(
186+
self::BEFORE_OPTION_VALUE_DELIMITER,
187+
$this->_entityModel->getMultipleValueSeparator(),
188+
$rowData['bundle_values']
189+
);
190+
$selections = explode(
191+
Product::PSEUDO_MULTI_LINE_SEPARATOR,
192+
$rowData['bundle_values']
193+
);
194+
} else {
195+
$selections = $rowData['bundle_values'];
196+
}
197+
193198
foreach ($selections as $selection) {
194-
$values = explode($this->_entityModel->getMultipleValueSeparator(), $selection);
195-
$option = $this->parseOption($values);
196-
if (isset($option['sku']) && isset($option['name'])) {
197-
if (!isset($this->_cachedOptions[$entityId])) {
198-
$this->_cachedOptions[$entityId] = [];
199-
}
199+
$option = is_string($selection)
200+
? $this->parseOption(explode($this->_entityModel->getMultipleValueSeparator(), $selection))
201+
: $selection;
202+
203+
if (isset($option['sku'], $option['name'])) {
200204
$this->_cachedSkus[] = $option['sku'];
201205
if (!isset($this->_cachedOptions[$entityId][$option['name']])) {
202206
$this->_cachedOptions[$entityId][$option['name']] = [];

app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesMissingRequiredFieldTest.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@
4545
<argument name="keyword" value="api-simple-product"/>
4646
</actionGroup>
4747

48-
<actionGroup ref="AdminCheckProductByIdOnProductGridActionGroup" stepKey="clickCheckbox1">
49-
<argument name="productId" value="$$createProductOne.id$$"/>
48+
<actionGroup ref="AdminCheckProductOnProductGridActionGroup" stepKey="clickCheckbox1">
49+
<argument name="product" value="$createProductOne$"/>
5050
</actionGroup>
5151

52-
<actionGroup ref="AdminCheckProductByIdOnProductGridActionGroup" stepKey="clickCheckbox2">
53-
<argument name="productId" value="$$createProductTwo.id$$"/>
52+
<actionGroup ref="AdminCheckProductOnProductGridActionGroup" stepKey="clickCheckbox2">
53+
<argument name="product" value="$createProductTwo$"/>
5454
</actionGroup>
5555

5656
<actionGroup ref="AdminClickMassUpdateProductAttributesActionGroup" stepKey="clickDropdown"/>

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

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,13 +1557,21 @@ public function getImagesFromRow(array $rowData)
15571557
$labels = [];
15581558
foreach ($this->_imagesArrayKeys as $column) {
15591559
if (!empty($rowData[$column])) {
1560-
$images[$column] = array_unique(
1561-
array_map(
1562-
'trim',
1563-
explode($this->getMultipleValueSeparator(), $rowData[$column])
1564-
)
1565-
);
1566-
1560+
if (is_string($rowData[$column])) {
1561+
$images[$column] = array_unique(
1562+
array_map(
1563+
'trim',
1564+
explode($this->getMultipleValueSeparator(), $rowData[$column])
1565+
)
1566+
);
1567+
} elseif (is_array($rowData[$column])) {
1568+
$images[$column] = array_unique(
1569+
array_map(
1570+
'trim',
1571+
$rowData[$column]
1572+
)
1573+
);
1574+
}
15671575
if (!empty($rowData[$column . '_label'])) {
15681576
$labels[$column] = $this->parseMultipleValues($rowData[$column . '_label']);
15691577

@@ -1764,7 +1772,12 @@ private function saveProductToWebsitePhase(array $rowData) : void
17641772
$this->websitesCache[$rowSku] = [];
17651773
}
17661774
if (!empty($rowData[self::COL_PRODUCT_WEBSITES])) {
1767-
$websiteCodes = explode($this->getMultipleValueSeparator(), $rowData[self::COL_PRODUCT_WEBSITES]);
1775+
$websiteCodes = is_string($rowData[self::COL_PRODUCT_WEBSITES])
1776+
? explode($this->getMultipleValueSeparator(), $rowData[self::COL_PRODUCT_WEBSITES])
1777+
: (is_array($rowData[self::COL_PRODUCT_WEBSITES])
1778+
? $rowData[self::COL_PRODUCT_WEBSITES]
1779+
: []);
1780+
17681781
foreach ($websiteCodes as $websiteCode) {
17691782
$websiteId = $this->storeResolver->getWebsiteCodeToId($websiteCode);
17701783
$this->websitesCache[$rowSku][$websiteId] = true;
@@ -2158,11 +2171,10 @@ private function getImagesHiddenStates($rowData)
21582171
*/
21592172
protected function processRowCategories($rowData)
21602173
{
2161-
$categoriesString = empty($rowData[self::COL_CATEGORY]) ? '' : $rowData[self::COL_CATEGORY];
21622174
$categoryIds = [];
2163-
if (!empty($categoriesString)) {
2175+
if (!empty($rowData[self::COL_CATEGORY])) {
21642176
$categoryIds = $this->categoryProcessor->upsertCategories(
2165-
$categoriesString,
2177+
$rowData[self::COL_CATEGORY],
21662178
$this->getMultipleValueSeparator()
21672179
);
21682180
foreach ($this->categoryProcessor->getFailedCategories() as $error) {
@@ -2821,7 +2833,13 @@ private function _parseAdditionalAttributes($rowData)
28212833
if (empty($rowData['additional_attributes'])) {
28222834
return $rowData;
28232835
}
2824-
$rowData = array_merge($rowData, $this->getAdditionalAttributes($rowData['additional_attributes']));
2836+
if (is_array($rowData['additional_attributes'])) {
2837+
foreach ($rowData['additional_attributes'] as $key => $value) {
2838+
$rowData[mb_strtolower($key)] = $value;
2839+
}
2840+
} else {
2841+
$rowData = array_merge($rowData, $this->getAdditionalAttributes($rowData['additional_attributes']));
2842+
}
28252843
return $rowData;
28262844
}
28272845

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

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,13 +1178,23 @@ protected function _isReadyForSaving(array &$options, array &$titles, array $typ
11781178
*/
11791179
protected function _getMultiRowFormat($rowData)
11801180
{
1181-
// Parse custom options.
1182-
$rowData = $this->_parseCustomOptions($rowData);
1183-
$multiRow = [];
1181+
if (!isset($rowData['custom_options'])) {
1182+
return [];
1183+
}
1184+
1185+
if (is_array($rowData['custom_options'])) {
1186+
$rowData = $this->parseStructuredCustomOptions($rowData);
1187+
} elseif (is_string($rowData['custom_options'])) {
1188+
$rowData = $this->_parseCustomOptions($rowData);
1189+
} else {
1190+
return [];
1191+
}
1192+
11841193
if (empty($rowData['custom_options']) || !is_array($rowData['custom_options'])) {
1185-
return $multiRow;
1194+
return [];
11861195
}
11871196

1197+
$multiRow = [];
11881198
$i = 0;
11891199
foreach ($rowData['custom_options'] as $name => $customOption) {
11901200
$i++;
@@ -1341,8 +1351,9 @@ protected function _importData()
13411351
if (array_key_exists('custom_options', $rowData)
13421352
&& (
13431353
$rowData['custom_options'] === null ||
1344-
trim($rowData['custom_options']) === '' ||
1345-
trim($rowData['custom_options']) === $this->_productEntity->getEmptyAttributeValueConstant()
1354+
(is_string($rowData['custom_options']) && trim($rowData['custom_options'])
1355+
=== $this->_productEntity->getEmptyAttributeValueConstant()) ||
1356+
!$rowData['custom_options']
13461357
)
13471358
) {
13481359
$optionsToRemove[] = $this->_rowProductId;
@@ -2102,6 +2113,39 @@ protected function _parseCustomOptions($rowData)
21022113
return $rowData;
21032114
}
21042115

2116+
/**
2117+
* Parse structured custom options to inner format.
2118+
*
2119+
* @param array $rowData
2120+
* @return array
2121+
*/
2122+
private function parseStructuredCustomOptions(array $rowData): array
2123+
{
2124+
if (empty($rowData['custom_options'])) {
2125+
return $rowData;
2126+
}
2127+
2128+
array_walk_recursive($rowData['custom_options'], function (&$value) {
2129+
$value = trim($value);
2130+
});
2131+
2132+
$customOptions = [];
2133+
foreach ($rowData['custom_options'] as $option) {
2134+
$optionName = $option['name'] ?? '';
2135+
if (!isset($customOptions[$optionName])) {
2136+
$customOptions[$optionName] = [];
2137+
}
2138+
if (isset($rowData[Product::COL_STORE_VIEW_CODE])) {
2139+
$option[self::COLUMN_STORE] = $rowData[Product::COL_STORE_VIEW_CODE];
2140+
}
2141+
$customOptions[$optionName][] = $option;
2142+
}
2143+
2144+
$rowData['custom_options'] = $customOptions;
2145+
2146+
return $rowData;
2147+
}
2148+
21052149
/**
21062150
* Clear product sku to id array.
21072151
*

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\CatalogImportExport\Model\Import\Product\Type;
77

88
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
9+
use Magento\CatalogImportExport\Model\Import\Product;
910
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
1011
use Magento\Eav\Model\Entity\Attribute\Source\Table;
1112
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory as AttributeOptionCollectionFactory;
@@ -21,6 +22,7 @@
2122
*
2223
* @SuppressWarnings(PHPMD.TooManyFields)
2324
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
25+
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
2426
* @since 100.0.2
2527
*/
2628
abstract class AbstractType
@@ -110,7 +112,7 @@ abstract class AbstractType
110112
/**
111113
* Product entity object.
112114
*
113-
* @var \Magento\CatalogImportExport\Model\Import\Product
115+
* @var Product
114116
*/
115117
protected $_entityModel;
116118

@@ -189,7 +191,7 @@ public function __construct(
189191
if (!isset($params[0])
190192
|| !isset($params[1])
191193
|| !is_object($params[0])
192-
|| !$params[0] instanceof \Magento\CatalogImportExport\Model\Import\Product
194+
|| !$params[0] instanceof Product
193195
) {
194196
throw new \Magento\Framework\Exception\LocalizedException(__('Please correct the parameters.'));
195197
}
@@ -258,7 +260,7 @@ public function retrieveAttribute($attributeCode, $attributeSet)
258260
protected function _getProductAttributes($attrSetData)
259261
{
260262
if (is_array($attrSetData)) {
261-
return $this->_attributes[$attrSetData[\Magento\CatalogImportExport\Model\Import\Product::COL_ATTR_SET]];
263+
return $this->_attributes[$attrSetData[Product::COL_ATTR_SET]];
262264
} else {
263265
return $this->_attributes[$attrSetData];
264266
}
@@ -569,23 +571,17 @@ public function isRowValid(array $rowData, $rowNum, $isNewProduct = true)
569571
{
570572
$error = false;
571573
$rowScope = $this->_entityModel->getRowScope($rowData);
572-
if (\Magento\CatalogImportExport\Model\Import\Product::SCOPE_NULL != $rowScope
573-
&& !empty($rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_SKU])
574-
) {
574+
if (Product::SCOPE_NULL != $rowScope && !empty($rowData[Product::COL_SKU])) {
575575
foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
576576
// check value for non-empty in the case of required attribute?
577-
if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
577+
if (isset($rowData[$attrCode]) && (!is_array($rowData[$attrCode]) && strlen($rowData[$attrCode]) > 0
578+
|| is_array($rowData[$attrCode]) && !empty($rowData[$attrCode]))) {
578579
$error |= !$this->_entityModel->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
579580
} elseif ($this->_isAttributeRequiredCheckNeeded($attrCode) && $attrParams['is_required']) {
580581
// For the default scope - if this is a new product or
581582
// for an old product, if the imported doc has the column present for the attrCode
582-
if (\Magento\CatalogImportExport\Model\Import\Product::SCOPE_DEFAULT == $rowScope &&
583-
($isNewProduct ||
584-
array_key_exists(
585-
$attrCode,
586-
$rowData
587-
))
588-
) {
583+
if (Product::SCOPE_DEFAULT == $rowScope &&
584+
($isNewProduct || array_key_exists($attrCode, $rowData))) {
589585
$this->_entityModel->addRowError(
590586
RowValidatorInterface::ERROR_VALUE_IS_REQUIRED,
591587
$rowNum,
@@ -631,7 +627,8 @@ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDe
631627
continue;
632628
}
633629
$attrCode = mb_strtolower($attrCode);
634-
if (isset($rowData[$attrCode]) && strlen(trim($rowData[$attrCode]))) {
630+
if (isset($rowData[$attrCode]) && ((is_array($rowData[$attrCode]) && !empty($rowData[$attrCode]))
631+
|| (!is_array($rowData[$attrCode]) && strlen(trim($rowData[$attrCode]))))) {
635632
if (in_array($attrParams['type'], ['select', 'boolean'])) {
636633
$resultAttrs[$attrCode] = $attrParams['options'][strtolower($rowData[$attrCode])];
637634
} elseif ('multiselect' == $attrParams['type']) {

0 commit comments

Comments
 (0)