Skip to content

Commit 5202113

Browse files
author
Slabko,Michael(mslabko)
committed
Merge pull request #564 from magento-troll/MAGETWO-41796
[Merchant Beta] MAGETWO-41796: Unable to import or export products with multi-select attributes
2 parents 1bc2180 + 5d19555 commit 5202113

File tree

9 files changed

+335
-145
lines changed

9 files changed

+335
-145
lines changed

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

+10-2
Original file line numberDiff line numberDiff line change
@@ -880,8 +880,16 @@ protected function collectRawData()
880880
ImportProduct::PAIR_NAME_VALUE_SEPARATOR . $attrValue;
881881
}
882882
$data[$itemId][$storeId][$fieldName] = $attrValue;
883-
} else {
884-
$this->collectMultiselectValues($item, $code, $storeId);
883+
}
884+
} else {
885+
$this->collectMultiselectValues($item, $code, $storeId);
886+
if (!empty($this->collectedMultiselectsData[$storeId][$itemId][$code])) {
887+
$additionalAttributes[$code] = $fieldName
888+
. ImportProduct::PAIR_NAME_VALUE_SEPARATOR
889+
. implode(
890+
ImportProduct::PSEUDO_MULTI_LINE_SEPARATOR,
891+
$this->collectedMultiselectsData[$storeId][$itemId][$code]
892+
);
885893
}
886894
}
887895
}

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

+18
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,22 @@ public function getParams();
2727
* @return mixed
2828
*/
2929
public function getParam($name);
30+
31+
/**
32+
* Get product type by name
33+
*
34+
* @param string $type
35+
*
36+
* @return mixed
37+
*/
38+
public function retrieveProductTypeByName($type);
39+
40+
/**
41+
* Get message template
42+
*
43+
* @param string $templateName
44+
*
45+
* @return mixed
46+
*/
47+
public function retrieveMessageTemplate($templateName);
3048
}

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

+23-54
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity i
226226
ValidatorInterface::ERROR_SUPER_PRODUCTS_SKU_NOT_FOUND => 'Product with specified super products SKU not found',
227227
ValidatorInterface::ERROR_MEDIA_DATA_INCOMPLETE => 'Media data is incomplete',
228228
ValidatorInterface::ERROR_INVALID_WEIGHT => 'Product weight is invalid',
229+
ValidatorInterface::ERROR_EXCEEDED_MAX_LENGTH => 'Attribute %s exceeded max length',
230+
ValidatorInterface::ERROR_INVALID_ATTRIBUTE_TYPE => 'Value for \'%s\' attribute contains incorrect value, acceptable values are in %s format',
231+
ValidatorInterface::ERROR_DUPLICATE_UNIQUE_ATTRIBUTE => 'Duplicated unique attribute',
232+
ValidatorInterface::ERROR_INVALID_ATTRIBUTE_OPTION => 'Value for \'%s\' attribute contains incorrect value, see acceptable values on settings specified for Admin',
229233
];
230234

231235
/**
@@ -236,8 +240,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity i
236240
protected $_fieldsMap = [
237241
'image' => 'base_image',
238242
'image_label' => "base_image_label",
239-
'image' => 'base_image',
240-
'image_label' => 'base_image_label',
241243
'thumbnail' => 'thumbnail_image',
242244
'thumbnail_label' => 'thumbnail_image_label',
243245
self::COL_MEDIA_IMAGE => 'additional_images',
@@ -670,53 +672,17 @@ public function __construct(
670672
* @param array $attrParams Attribute params
671673
* @param array $rowData Row data
672674
* @param int $rowNum
673-
*
674-
* @return boolean
675-
*
676-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
675+
* @return bool
677676
*/
678677
public function isAttributeValid($attrCode, array $attrParams, array $rowData, $rowNum)
679678
{
680-
switch ($attrParams['type']) {
681-
case 'varchar':
682-
$val = $this->string->cleanString($rowData[$attrCode]);
683-
$valid = $this->string->strlen($val) < self::DB_MAX_VARCHAR_LENGTH;
684-
break;
685-
case 'decimal':
686-
$val = trim($rowData[$attrCode]);
687-
$valid = is_numeric($val);
688-
break;
689-
case 'select':
690-
case 'multiselect':
691-
$valid = isset($attrParams['options'][strtolower($rowData[$attrCode])]);
692-
break;
693-
case 'int':
694-
$val = trim($rowData[$attrCode]);
695-
$valid = (string)(int)$val === $val;
696-
break;
697-
case 'datetime':
698-
$val = trim($rowData[$attrCode]);
699-
$valid = strtotime($val) !== false;
700-
break;
701-
case 'text':
702-
$val = $this->string->cleanString($rowData[$attrCode]);
703-
$valid = $this->string->strlen($val) < self::DB_MAX_TEXT_LENGTH;
704-
break;
705-
default:
706-
$valid = true;
707-
break;
708-
}
709-
710-
if (!$valid) {
711-
$this->addRowError(__("Please correct the value for '%s'."), $rowNum, $attrCode);
712-
} elseif (!empty($attrParams['is_unique'])) {
713-
if (isset($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]]) && ($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] != $rowData[self::COL_SKU])) {
714-
$this->addRowError(__("Duplicate Unique Attribute for '%s'"), $rowNum, $attrCode);
715-
return false;
679+
if (!$this->validator->isAttributeValid($attrCode, $attrParams, $rowData)) {
680+
foreach ($this->validator->getMessages() as $message) {
681+
$this->addRowError($message, $rowNum, $attrCode);
716682
}
717-
$this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] = $rowData[self::COL_SKU];
683+
return false;
718684
}
719-
return (bool)$valid;
685+
return true;
720686
}
721687

722688
/**
@@ -1571,16 +1537,7 @@ protected function _saveProducts()
15711537
}
15721538
}
15731539
foreach ($storeIds as $storeId) {
1574-
if ('multiselect' == $attribute->getFrontendInput()) {
1575-
if (!isset($attributes[$attrTable][$rowSku][$attrId][$storeId])) {
1576-
$attributes[$attrTable][$rowSku][$attrId][$storeId] = '';
1577-
} else {
1578-
$attributes[$attrTable][$rowSku][$attrId][$storeId] .= ',';
1579-
}
1580-
$attributes[$attrTable][$rowSku][$attrId][$storeId] .= $attrValue;
1581-
} else {
1582-
$attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue;
1583-
}
1540+
$attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue;
15841541
}
15851542
// restore 'backend_model' to avoid 'default' setting
15861543
$attribute->setBackendModel($backModel);
@@ -2310,4 +2267,16 @@ public function getParam($name)
23102267
{
23112268
return isset($this->_parameters[$name]) ? $this->_parameters[$name] : null;
23122269
}
2270+
2271+
/**
2272+
* @param string $name
2273+
* @return mixed
2274+
*/
2275+
public function retrieveProductTypeByName($name)
2276+
{
2277+
if (isset($this->_productTypeModels[$name])) {
2278+
return $this->_productTypeModels[$name];
2279+
}
2280+
return null;
2281+
}
23132282
}

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

+8
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ interface RowValidatorInterface extends \Magento\Framework\Validator\ValidatorIn
6161

6262
const ERROR_INVALID_WEIGHT = 'invalidWeight';
6363

64+
const ERROR_EXCEEDED_MAX_LENGTH = 'exceededMaxLength';
65+
66+
const ERROR_INVALID_ATTRIBUTE_TYPE = 'invalidAttributeType';
67+
68+
const ERROR_DUPLICATE_UNIQUE_ATTRIBUTE = 'duplicatedUniqueAttribute';
69+
70+
const ERROR_INVALID_ATTRIBUTE_OPTION = 'absentAttributeOption';
71+
6472
/**
6573
* Value that means all entities (e.g. websites, groups etc.)
6674
*/

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

+46-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
namespace Magento\CatalogImportExport\Model\Import\Product\Type;
77

8+
use Magento\CatalogImportExport\Model\Import\Product;
9+
810
/**
911
* Import entity abstract product type model
1012
*
@@ -19,6 +21,13 @@ abstract class AbstractType
1921
*/
2022
public static $commonAttributesCache = [];
2123

24+
/**
25+
* Attribute Code to Id cache
26+
*
27+
* @var array
28+
*/
29+
public static $attributeCodeToId = [];
30+
2231
/**
2332
* Product type attribute sets and attributes parameters.
2433
*
@@ -358,6 +367,16 @@ public function isRowValid(array $rowData, $rowNum, $isNewProduct = true)
358367
// check value for non-empty in the case of required attribute?
359368
if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
360369
$error |= !$this->_entityModel->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
370+
$resultAttrs[$attrCode] = 'select' == $attrParams['type'] ? $attrParams['options'][strtolower(
371+
$rowData[$attrCode]
372+
)] : $rowData[$attrCode];
373+
if ('multiselect' == $attrParams['type']) {
374+
$resultAttrs[$attrCode] = [];
375+
foreach (explode('|', $rowData[$attrCode]) as $value) {
376+
$resultAttrs[$attrCode][] = $attrParams['options'][strtolower($value)];
377+
}
378+
$resultAttrs[$attrCode] = implode(',', $resultAttrs[$attrCode]);
379+
}
361380
} elseif ($this->_isAttributeRequiredCheckNeeded($attrCode) && $attrParams['is_required']) {
362381
// For the default scope - if this is a new product or
363382
// for an old product, if the imported doc has the column present for the attrCode
@@ -412,10 +431,16 @@ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDe
412431
foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
413432
if (!$attrParams['is_static']) {
414433
if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
415-
$resultAttrs[$attrCode] = 'select' == $attrParams['type'] ||
416-
'multiselect' == $attrParams['type'] ? $attrParams['options'][strtolower(
417-
$rowData[$attrCode]
418-
)] : $rowData[$attrCode];
434+
$resultAttrs[$attrCode] = 'select' == $attrParams['type']
435+
? $attrParams['options'][strtolower($rowData[$attrCode])]
436+
: $rowData[$attrCode];
437+
if ('multiselect' == $attrParams['type']) {
438+
$resultAttrs[$attrCode] = [];
439+
foreach (explode(Product::PSEUDO_MULTI_LINE_SEPARATOR, $rowData[$attrCode]) as $value) {
440+
$resultAttrs[$attrCode][] = $attrParams['options'][strtolower($value)];
441+
}
442+
$resultAttrs[$attrCode] = implode(',', $resultAttrs[$attrCode]);
443+
}
419444
} elseif (array_key_exists($attrCode, $rowData)) {
420445
$resultAttrs[$attrCode] = $rowData[$attrCode];
421446
} elseif ($withDefaultValue && null !== $attrParams['default_value']) {
@@ -452,4 +477,21 @@ public function saveData()
452477
{
453478
return $this;
454479
}
480+
481+
/**
482+
* Retrieve attribute from cache
483+
*
484+
* @param string $attributeCode
485+
* @return mixed
486+
*/
487+
public function retrieveAttributeFromCache($attributeCode)
488+
{
489+
if (isset(self::$attributeCodeToId[$attributeCode])) {
490+
$id = self::$attributeCodeToId[$attributeCode];
491+
if (isset(self::$commonAttributesCache[$id])) {
492+
return self::$commonAttributesCache[$id];
493+
}
494+
}
495+
return [];
496+
}
455497
}

0 commit comments

Comments
 (0)