@@ -137,6 +137,11 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
137
137
*/
138
138
const INVENTORY_USE_CONFIG_PREFIX = 'use_config_ ' ;
139
139
140
+ /**
141
+ * Url key attribute code
142
+ */
143
+ const URL_KEY = 'url_key ' ;
144
+
140
145
/**
141
146
* Attribute cache
142
147
*
@@ -233,6 +238,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
233
238
ValidatorInterface::ERROR_MEDIA_PATH_NOT_ACCESSIBLE => 'Imported resource (image) does not exist in the local media storage ' ,
234
239
ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE => 'Imported resource (image) could not be downloaded from external resource due to timeout or access permissions ' ,
235
240
ValidatorInterface::ERROR_INVALID_WEIGHT => 'Product weight is invalid ' ,
241
+ ValidatorInterface::ERROR_DUPLICATE_URL_KEY => 'Specified url key is already exist ' ,
236
242
];
237
243
238
244
/**
@@ -502,12 +508,24 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
502
508
*/
503
509
protected $ categoryProcessor ;
504
510
511
+ /** @var \Magento\Framework\App\Config\ScopeConfigInterface */
512
+ protected $ scopeConfig ;
513
+
514
+ /** @var \Magento\Catalog\Model\Product\Url */
515
+ protected $ productUrl ;
516
+
505
517
/** @var array */
506
518
protected $ websitesCache = [];
507
519
508
520
/** @var array */
509
521
protected $ categoriesCache = [];
510
522
523
+ /** @var array */
524
+ protected $ productUrlSuffix = [];
525
+
526
+ /** @var array */
527
+ protected $ productUrlKeys = [];
528
+
511
529
/**
512
530
* Instance of product tax class processor.
513
531
*
@@ -561,6 +579,12 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
561
579
*/
562
580
protected $ cachedImages = null ;
563
581
582
+ /** @var array */
583
+ protected $ urlKeys = [];
584
+
585
+ /** @var array */
586
+ protected $ rowNumbers = [];
587
+
564
588
/**
565
589
* @var \Magento\Framework\Model\Entity\MetadataPool
566
590
*/
@@ -601,6 +625,8 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
601
625
* @param ObjectRelationProcessor $objectRelationProcessor
602
626
* @param TransactionManagerInterface $transactionManager
603
627
* @param Product\TaxClassProcessor $taxClassProcessor
628
+ * @param \Magento\Framework\Model\Entity\MetadataPool $metadataPool
629
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
604
630
* @param array $data
605
631
* @throws \Magento\Framework\Exception\LocalizedException
606
632
*
@@ -642,6 +668,8 @@ public function __construct(
642
668
TransactionManagerInterface $ transactionManager ,
643
669
Product \TaxClassProcessor $ taxClassProcessor ,
644
670
\Magento \Framework \Model \Entity \MetadataPool $ metadataPool ,
671
+ \Magento \Framework \App \Config \ScopeConfigInterface $ scopeConfig ,
672
+ \Magento \Catalog \Model \Product \Url $ productUrl ,
645
673
array $ data = []
646
674
) {
647
675
$ this ->_eventManager = $ eventManager ;
@@ -670,6 +698,8 @@ public function __construct(
670
698
$ this ->transactionManager = $ transactionManager ;
671
699
$ this ->taxClassProcessor = $ taxClassProcessor ;
672
700
$ this ->metadataPool = $ metadataPool ;
701
+ $ this ->scopeConfig = $ scopeConfig ;
702
+ $ this ->productUrl = $ productUrl ;
673
703
parent ::__construct (
674
704
$ jsonHelper ,
675
705
$ importExportData ,
@@ -1933,7 +1963,7 @@ protected function _saveStockItem()
1933
1963
$ productIdsToReindex [] = $ row ['product_id ' ];
1934
1964
1935
1965
$ row ['website_id ' ] = $ this ->stockConfiguration ->getDefaultScopeId ();
1936
- $ row ['stock_id ' ] = $ this ->stockRegistry ->getStock ($ row [ ' website_id ' ] )->getStockId ();
1966
+ $ row ['stock_id ' ] = $ this ->stockRegistry ->getStock ()->getStockId ();
1937
1967
1938
1968
$ stockItemDo = $ this ->stockRegistry ->getStockItem ($ row ['product_id ' ], $ row ['website_id ' ]);
1939
1969
$ existStockData = $ stockItemDo ->getData ();
@@ -1986,11 +2016,8 @@ protected function _saveStockItem()
1986
2016
*/
1987
2017
public function retrieveAttributeByCode ($ attrCode )
1988
2018
{
1989
- if (!$ this ->_resource ) {
1990
- $ this ->_resource = $ this ->_resourceFactory ->create ();
1991
- }
1992
2019
if (!isset ($ this ->_attributeCache [$ attrCode ])) {
1993
- $ this ->_attributeCache [$ attrCode ] = $ this ->_resource ->getAttribute ($ attrCode );
2020
+ $ this ->_attributeCache [$ attrCode ] = $ this ->getResource () ->getAttribute ($ attrCode );
1994
2021
}
1995
2022
return $ this ->_attributeCache [$ attrCode ];
1996
2023
}
@@ -2201,7 +2228,25 @@ public function validateRow(array $rowData, $rowNum)
2201
2228
}
2202
2229
// validate custom options
2203
2230
$ this ->getOptionEntity ()->validateRow ($ rowData , $ rowNum );
2204
-
2231
+ if (!empty ($ rowData [self ::URL_KEY ]) || !empty ($ rowData [self ::COL_NAME ])) {
2232
+ $ urlKey = $ this ->getUrlKey ($ rowData );
2233
+ $ storeCodes = empty ($ rowData [self ::COL_STORE_VIEW_CODE ])
2234
+ ? array_flip ($ this ->storeResolver ->getStoreCodeToId ())
2235
+ : explode ($ this ->getMultipleValueSeparator (), $ rowData [self ::COL_STORE_VIEW_CODE ]);
2236
+ foreach ($ storeCodes as $ storeCode ) {
2237
+ $ storeId = $ this ->storeResolver ->getStoreCodeToId ($ storeCode );
2238
+ $ productUrlSuffix = $ this ->getProductUrlSuffix ($ storeId );
2239
+ $ urlPath = $ urlKey . $ productUrlSuffix ;
2240
+ if (empty ($ this ->urlKeys [$ storeId ][$ urlPath ])
2241
+ || ($ this ->urlKeys [$ storeId ][$ urlPath ] == $ rowData [self ::COL_SKU ])
2242
+ ) {
2243
+ $ this ->urlKeys [$ storeId ][$ urlPath ] = $ rowData [self ::COL_SKU ];
2244
+ $ this ->rowNumbers [$ storeId ][$ urlPath ] = $ rowNum ;
2245
+ } else {
2246
+ $ this ->addRowError (ValidatorInterface::ERROR_DUPLICATE_URL_KEY , $ rowNum );
2247
+ }
2248
+ }
2249
+ }
2205
2250
return !$ this ->getErrorAggregator ()->isRowInvalid ($ rowNum );
2206
2251
}
2207
2252
@@ -2306,7 +2351,79 @@ protected function _saveValidatedBunches()
2306
2351
$ this ->validateRow ($ rowData , $ source ->key ());
2307
2352
$ source ->next ();
2308
2353
}
2354
+ $ this ->checkUrlKeyDuplicates ();
2309
2355
$ this ->getOptionEntity ()->validateAmbiguousData ();
2310
2356
return parent ::_saveValidatedBunches ();
2311
2357
}
2358
+
2359
+ /**
2360
+ * Check that url_keys are not assigned to other products in DB
2361
+ *
2362
+ * @return void
2363
+ */
2364
+ protected function checkUrlKeyDuplicates ()
2365
+ {
2366
+ $ resource = $ this ->getResource ();
2367
+ foreach ($ this ->urlKeys as $ storeId => $ urlKeys ) {
2368
+ $ urlKeyDuplicates = $ this ->_connection ->fetchAssoc (
2369
+ $ this ->_connection ->select ()->from (
2370
+ ['url_rewrite ' => $ resource ->getTable ('url_rewrite ' )],
2371
+ ['request_path ' , 'store_id ' ]
2372
+ )->joinLeft (
2373
+ ['cpe ' => $ resource ->getTable ('catalog_product_entity ' )],
2374
+ "cpe.entity_id = url_rewrite.entity_id "
2375
+ )->where ('request_path IN (?) ' , array_keys ($ urlKeys ))
2376
+ ->where ('store_id IN (?) ' , $ storeId )
2377
+ ->where ('cpe.sku not in (?) ' , array_values ($ urlKeys ))
2378
+ );
2379
+ foreach ($ urlKeyDuplicates as $ entityData ) {
2380
+ $ rowNum = $ this ->rowNumbers [$ entityData ['store_id ' ]][$ entityData ['request_path ' ]];
2381
+ $ this ->addRowError (ValidatorInterface::ERROR_DUPLICATE_URL_KEY , $ rowNum );
2382
+ }
2383
+ }
2384
+ }
2385
+
2386
+ /**
2387
+ * Retrieve product rewrite suffix for store
2388
+ *
2389
+ * @param int $storeId
2390
+ * @return string
2391
+ */
2392
+ protected function getProductUrlSuffix ($ storeId = null )
2393
+ {
2394
+ if (!isset ($ this ->productUrlSuffix [$ storeId ])) {
2395
+ $ this ->productUrlSuffix [$ storeId ] = $ this ->scopeConfig ->getValue (
2396
+ \Magento \CatalogUrlRewrite \Model \ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX ,
2397
+ \Magento \Store \Model \ScopeInterface::SCOPE_STORE ,
2398
+ $ storeId
2399
+ );
2400
+ }
2401
+ return $ this ->productUrlSuffix [$ storeId ];
2402
+ }
2403
+
2404
+ /**
2405
+ * @param array $rowData
2406
+ * @return string
2407
+ */
2408
+ protected function getUrlKey ($ rowData )
2409
+ {
2410
+ if (!empty ($ rowData [self ::URL_KEY ])) {
2411
+ $ this ->productUrlKeys [$ rowData [self ::COL_SKU ]] = $ rowData [self ::URL_KEY ];
2412
+ }
2413
+ $ urlKey = !empty ($ this ->productUrlKeys [$ rowData [self ::COL_SKU ]])
2414
+ ? $ this ->productUrlKeys [$ rowData [self ::COL_SKU ]]
2415
+ : $ this ->productUrl ->formatUrlKey ($ rowData [self ::COL_NAME ]);
2416
+ return $ urlKey ;
2417
+ }
2418
+
2419
+ /**
2420
+ * @return Proxy\Product\ResourceModel
2421
+ */
2422
+ protected function getResource ()
2423
+ {
2424
+ if (!$ this ->_resource ) {
2425
+ $ this ->_resource = $ this ->_resourceFactory ->create ();
2426
+ }
2427
+ return $ this ->_resource ;
2428
+ }
2312
2429
}
0 commit comments