12
12
use Magento \Framework \App \ResourceConnection ;
13
13
use Magento \ImportExport \Model \Import \ErrorProcessing \ProcessingErrorAggregatorInterface ;
14
14
use Magento \Catalog \Api \Data \ProductInterface ;
15
+ use Magento \Catalog \Model \ResourceModel \Product \Option \Value \Collection as ProductOptionValueCollection ;
16
+ use Magento \Catalog \Model \ResourceModel \Product \Option \Value \CollectionFactory as ProductOptionValueCollectionFactory ;
15
17
16
18
/**
17
19
* Entity class which provide possibility to import product custom options
@@ -320,6 +322,16 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
320
322
*/
321
323
private $ productEntityIdentifierField ;
322
324
325
+ /**
326
+ * @var ProductOptionValueCollectionFactory
327
+ */
328
+ private $ productOptionValueCollectionFactory ;
329
+
330
+ /**
331
+ * @var array
332
+ */
333
+ private $ optionTypeTitles ;
334
+
323
335
/**
324
336
* @param \Magento\ImportExport\Model\ResourceModel\Import\Data $importData
325
337
* @param ResourceConnection $resource
@@ -333,6 +345,7 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
333
345
* @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $dateTime
334
346
* @param ProcessingErrorAggregatorInterface $errorAggregator
335
347
* @param array $data
348
+ * @param ProductOptionValueCollectionFactory $productOptionValueCollectionFactory
336
349
* @throws \Magento\Framework\Exception\LocalizedException
337
350
*
338
351
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
@@ -349,7 +362,8 @@ public function __construct(
349
362
\Magento \Framework \App \Config \ScopeConfigInterface $ scopeConfig ,
350
363
\Magento \Framework \Stdlib \DateTime \TimezoneInterface $ dateTime ,
351
364
ProcessingErrorAggregatorInterface $ errorAggregator ,
352
- array $ data = []
365
+ array $ data = [],
366
+ ProductOptionValueCollectionFactory $ productOptionValueCollectionFactory = null
353
367
) {
354
368
$ this ->_resource = $ resource ;
355
369
$ this ->_catalogData = $ catalogData ;
@@ -360,6 +374,8 @@ public function __construct(
360
374
$ this ->_colIteratorFactory = $ colIteratorFactory ;
361
375
$ this ->_scopeConfig = $ scopeConfig ;
362
376
$ this ->dateTime = $ dateTime ;
377
+ $ this ->productOptionValueCollectionFactory = $ productOptionValueCollectionFactory
378
+ ?: \Magento \Framework \App \ObjectManager::getInstance ()->get (ProductOptionValueCollectionFactory::class);
363
379
364
380
if (isset ($ data ['connection ' ])) {
365
381
$ this ->_connection = $ data ['connection ' ];
@@ -1121,7 +1137,7 @@ private function processOptionRow($name, $optionRow)
1121
1137
if (isset ($ optionRow ['price ' ])) {
1122
1138
$ percent_suffix = '' ;
1123
1139
if (isset ($ optionRow ['price_type ' ]) && $ optionRow ['price_type ' ] == 'percent ' ) {
1124
- $ percent_suffix = '% ' ;
1140
+ $ percent_suffix = '% ' ;
1125
1141
}
1126
1142
$ result [self ::COLUMN_ROW_PRICE ] = $ optionRow ['price ' ] . $ percent_suffix ;
1127
1143
}
@@ -1230,6 +1246,7 @@ protected function _importData()
1230
1246
if ($ this ->_isReadyForSaving ($ options , $ titles , $ typeValues )) {
1231
1247
if ($ this ->getBehavior () == \Magento \ImportExport \Model \Import::BEHAVIOR_APPEND ) {
1232
1248
$ this ->_compareOptionsWithExisting ($ options , $ titles , $ prices , $ typeValues );
1249
+ $ this ->restoreOriginalOptionTypeIds ($ typeValues , $ typePrices , $ typeTitles );
1233
1250
}
1234
1251
1235
1252
$ this ->_saveOptions (
@@ -1296,12 +1313,12 @@ protected function _collectOptionMainData(
1296
1313
$ optionData = $ this ->_getOptionData ($ rowData , $ this ->_rowProductId , $ nextOptionId , $ this ->_rowType );
1297
1314
1298
1315
if (!$ this ->_isRowHasSpecificType (
1299
- $ this ->_rowType
1300
- ) && ($ priceData = $ this ->_getPriceData (
1301
- $ rowData ,
1302
- $ nextOptionId ,
1303
- $ this ->_rowType
1304
- ))
1316
+ $ this ->_rowType
1317
+ ) && ($ priceData = $ this ->_getPriceData (
1318
+ $ rowData ,
1319
+ $ nextOptionId ,
1320
+ $ this ->_rowType
1321
+ ))
1305
1322
) {
1306
1323
$ prices [$ nextOptionId ] = $ priceData ;
1307
1324
}
@@ -1434,6 +1451,68 @@ protected function _compareOptionsWithExisting(array &$options, array &$titles,
1434
1451
return $ this ;
1435
1452
}
1436
1453
1454
+ /**
1455
+ * Restore original IDs for existing option types.
1456
+ *
1457
+ * Warning: arguments are modified by reference
1458
+ *
1459
+ * @param array $typeValues
1460
+ * @param array $typePrices
1461
+ * @param array $typeTitles
1462
+ * @return void
1463
+ */
1464
+ private function restoreOriginalOptionTypeIds (array &$ typeValues , array &$ typePrices , array &$ typeTitles )
1465
+ {
1466
+ foreach ($ typeValues as $ optionId => &$ optionTypes ) {
1467
+ foreach ($ optionTypes as &$ optionType ) {
1468
+ $ optionTypeId = $ optionType ['option_type_id ' ];
1469
+ foreach ($ typeTitles [$ optionTypeId ] as $ storeId => $ optionTypeTitle ) {
1470
+ $ existingTypeId = $ this ->getExistingOptionTypeId ($ optionId , $ storeId , $ optionTypeTitle );
1471
+ if ($ existingTypeId ) {
1472
+ $ optionType ['option_type_id ' ] = $ existingTypeId ;
1473
+ $ typeTitles [$ existingTypeId ] = $ typeTitles [$ optionTypeId ];
1474
+ unset($ typeTitles [$ optionTypeId ]);
1475
+ $ typePrices [$ existingTypeId ] = $ typePrices [$ optionTypeId ];
1476
+ unset($ typePrices [$ optionTypeId ]);
1477
+ // If option type titles match at least in one store, consider current option type as existing
1478
+ break ;
1479
+ }
1480
+ }
1481
+ }
1482
+ }
1483
+ }
1484
+
1485
+ /**
1486
+ * Identify ID of the provided option type by its title in the specified store.
1487
+ *
1488
+ * @param int $optionId
1489
+ * @param int $storeId
1490
+ * @param string $optionTypeTitle
1491
+ * @return int|null
1492
+ */
1493
+ private function getExistingOptionTypeId ($ optionId , $ storeId , $ optionTypeTitle )
1494
+ {
1495
+ if (!isset ($ this ->optionTypeTitles [$ storeId ])) {
1496
+ /** @var ProductOptionValueCollection $optionTypeCollection */
1497
+ $ optionTypeCollection = $ this ->productOptionValueCollectionFactory ->create ();
1498
+ $ optionTypeCollection ->addTitleToResult ($ storeId );
1499
+ /** @var \Magento\Catalog\Model\Product\Option\Value $type */
1500
+ foreach ($ optionTypeCollection as $ type ) {
1501
+ $ this ->optionTypeTitles [$ storeId ][$ type ->getOptionId ()][$ type ->getId ()] = $ type ->getTitle ();
1502
+ }
1503
+ }
1504
+ if (isset ($ this ->optionTypeTitles [$ storeId ][$ optionId ])
1505
+ && is_array ($ this ->optionTypeTitles [$ storeId ][$ optionId ])
1506
+ ) {
1507
+ foreach ($ this ->optionTypeTitles [$ storeId ][$ optionId ] as $ optionTypeId => $ currentTypeTitle ) {
1508
+ if ($ optionTypeTitle === $ currentTypeTitle ) {
1509
+ return $ optionTypeId ;
1510
+ }
1511
+ }
1512
+ }
1513
+ return null ;
1514
+ }
1515
+
1437
1516
/**
1438
1517
* Parse required data from current row and store to class internal variables some data
1439
1518
* for underlying dependent rows
@@ -1565,13 +1644,13 @@ protected function _getOptionData(array $rowData, $productId, $optionId, $type)
1565
1644
protected function _getPriceData (array $ rowData , $ optionId , $ type )
1566
1645
{
1567
1646
if (in_array (
1568
- 'price ' ,
1569
- $ this ->_specificTypes [$ type ]
1570
- ) && isset (
1571
- $ rowData [self ::COLUMN_PREFIX . 'price ' ]
1572
- ) && strlen (
1573
- $ rowData [self ::COLUMN_PREFIX . 'price ' ]
1574
- ) > 0
1647
+ 'price ' ,
1648
+ $ this ->_specificTypes [$ type ]
1649
+ ) && isset (
1650
+ $ rowData [self ::COLUMN_PREFIX . 'price ' ]
1651
+ ) && strlen (
1652
+ $ rowData [self ::COLUMN_PREFIX . 'price ' ]
1653
+ ) > 0
1575
1654
) {
1576
1655
$ priceData = [
1577
1656
'option_id ' => $ optionId ,
@@ -1821,13 +1900,17 @@ protected function _updateProducts(array $data)
1821
1900
* @return array
1822
1901
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
1823
1902
*/
1824
- protected function _parseCustomOptions ($ rowData )
1903
+ protected function _parseCustomOptions ($ rowData )
1825
1904
{
1826
1905
$ beforeOptionValueSkuDelimiter = '; ' ;
1827
1906
if (empty ($ rowData ['custom_options ' ])) {
1828
1907
return $ rowData ;
1829
1908
}
1830
- $ rowData ['custom_options ' ] = str_replace ($ beforeOptionValueSkuDelimiter , $ this ->_productEntity ->getMultipleValueSeparator (), $ rowData ['custom_options ' ]);
1909
+ $ rowData ['custom_options ' ] = str_replace (
1910
+ $ beforeOptionValueSkuDelimiter ,
1911
+ $ this ->_productEntity ->getMultipleValueSeparator (),
1912
+ $ rowData ['custom_options ' ]
1913
+ );
1831
1914
$ options = [];
1832
1915
$ optionValues = explode (Product::PSEUDO_MULTI_LINE_SEPARATOR , $ rowData ['custom_options ' ]);
1833
1916
$ k = 0 ;
@@ -1839,7 +1922,7 @@ protected function _parseCustomOptions($rowData)
1839
1922
if (!empty ($ nameAndValue )) {
1840
1923
$ value = isset ($ nameAndValue [1 ]) ? $ nameAndValue [1 ] : '' ;
1841
1924
$ value = trim ($ value );
1842
- $ fieldName = trim ($ nameAndValue [0 ]);
1925
+ $ fieldName = trim ($ nameAndValue [0 ]);
1843
1926
if ($ value && ($ fieldName == 'name ' )) {
1844
1927
if ($ name != $ value ) {
1845
1928
$ name = $ value ;
@@ -1878,7 +1961,7 @@ private function getProductEntityLinkField()
1878
1961
{
1879
1962
if (!$ this ->productEntityLinkField ) {
1880
1963
$ this ->productEntityLinkField = $ this ->getMetadataPool ()
1881
- ->getMetadata (\ Magento \ Catalog \ Api \ Data \ ProductInterface::class)
1964
+ ->getMetadata (ProductInterface::class)
1882
1965
->getLinkField ();
1883
1966
}
1884
1967
return $ this ->productEntityLinkField ;
@@ -1893,7 +1976,7 @@ private function getProductIdentifierField()
1893
1976
{
1894
1977
if (!$ this ->productEntityIdentifierField ) {
1895
1978
$ this ->productEntityIdentifierField = $ this ->getMetadataPool ()
1896
- ->getMetadata (\ Magento \ Catalog \ Api \ Data \ ProductInterface::class)
1979
+ ->getMetadata (ProductInterface::class)
1897
1980
->getIdentifierField ();
1898
1981
}
1899
1982
return $ this ->productEntityIdentifierField ;
0 commit comments