@@ -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
* @param \Magento\Framework\Json\Helper\Data $jsonHelper
566
590
* @param \Magento\ImportExport\Helper\Data $importExportData
@@ -596,6 +620,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
596
620
* @param ObjectRelationProcessor $objectRelationProcessor
597
621
* @param TransactionManagerInterface $transactionManager
598
622
* @param Product\TaxClassProcessor $taxClassProcessor
623
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
599
624
* @param array $data
600
625
* @throws \Magento\Framework\Exception\LocalizedException
601
626
*
@@ -636,6 +661,8 @@ public function __construct(
636
661
ObjectRelationProcessor $ objectRelationProcessor ,
637
662
TransactionManagerInterface $ transactionManager ,
638
663
Product \TaxClassProcessor $ taxClassProcessor ,
664
+ \Magento \Framework \App \Config \ScopeConfigInterface $ scopeConfig ,
665
+ \Magento \Catalog \Model \Product \Url $ productUrl ,
639
666
array $ data = []
640
667
) {
641
668
$ this ->_eventManager = $ eventManager ;
@@ -663,6 +690,8 @@ public function __construct(
663
690
$ this ->objectRelationProcessor = $ objectRelationProcessor ;
664
691
$ this ->transactionManager = $ transactionManager ;
665
692
$ this ->taxClassProcessor = $ taxClassProcessor ;
693
+ $ this ->scopeConfig = $ scopeConfig ;
694
+ $ this ->productUrl = $ productUrl ;
666
695
parent ::__construct (
667
696
$ jsonHelper ,
668
697
$ importExportData ,
@@ -1999,11 +2028,8 @@ protected function _saveStockItem()
1999
2028
*/
2000
2029
public function retrieveAttributeByCode ($ attrCode )
2001
2030
{
2002
- if (!$ this ->_resource ) {
2003
- $ this ->_resource = $ this ->_resourceFactory ->create ();
2004
- }
2005
2031
if (!isset ($ this ->_attributeCache [$ attrCode ])) {
2006
- $ this ->_attributeCache [$ attrCode ] = $ this ->_resource ->getAttribute ($ attrCode );
2032
+ $ this ->_attributeCache [$ attrCode ] = $ this ->getResource () ->getAttribute ($ attrCode );
2007
2033
}
2008
2034
return $ this ->_attributeCache [$ attrCode ];
2009
2035
}
@@ -2214,7 +2240,25 @@ public function validateRow(array $rowData, $rowNum)
2214
2240
}
2215
2241
// validate custom options
2216
2242
$ this ->getOptionEntity ()->validateRow ($ rowData , $ rowNum );
2217
-
2243
+ if (!empty ($ rowData [self ::URL_KEY ]) || !empty ($ rowData [self ::COL_NAME ])) {
2244
+ $ urlKey = $ this ->getUrlKey ($ rowData );
2245
+ $ storeCodes = empty ($ rowData [self ::COL_STORE_VIEW_CODE ])
2246
+ ? array_flip ($ this ->storeResolver ->getStoreCodeToId ())
2247
+ : explode ($ this ->getMultipleValueSeparator (), $ rowData [self ::COL_STORE_VIEW_CODE ]);
2248
+ foreach ($ storeCodes as $ storeCode ) {
2249
+ $ storeId = $ this ->storeResolver ->getStoreCodeToId ($ storeCode );
2250
+ $ productUrlSuffix = $ this ->getProductUrlSuffix ($ storeId );
2251
+ $ urlPath = $ urlKey . $ productUrlSuffix ;
2252
+ if (empty ($ this ->urlKeys [$ storeId ][$ urlPath ])
2253
+ || ($ this ->urlKeys [$ storeId ][$ urlPath ] == $ rowData [self ::COL_SKU ])
2254
+ ) {
2255
+ $ this ->urlKeys [$ storeId ][$ urlPath ] = $ rowData [self ::COL_SKU ];
2256
+ $ this ->rowNumbers [$ storeId ][$ urlPath ] = $ rowNum ;
2257
+ } else {
2258
+ $ this ->addRowError (ValidatorInterface::ERROR_DUPLICATE_URL_KEY , $ rowNum );
2259
+ }
2260
+ }
2261
+ }
2218
2262
return !$ this ->getErrorAggregator ()->isRowInvalid ($ rowNum );
2219
2263
}
2220
2264
@@ -2319,7 +2363,79 @@ protected function _saveValidatedBunches()
2319
2363
$ this ->validateRow ($ rowData , $ source ->key ());
2320
2364
$ source ->next ();
2321
2365
}
2366
+ $ this ->checkUrlKeyDuplicates ();
2322
2367
$ this ->getOptionEntity ()->validateAmbiguousData ();
2323
2368
return parent ::_saveValidatedBunches ();
2324
2369
}
2370
+
2371
+ /**
2372
+ * Check that url_keys are not assigned to other products in DB
2373
+ *
2374
+ * @return void
2375
+ */
2376
+ protected function checkUrlKeyDuplicates ()
2377
+ {
2378
+ $ resource = $ this ->getResource ();
2379
+ foreach ($ this ->urlKeys as $ storeId => $ urlKeys ) {
2380
+ $ urlKeyDuplicates = $ this ->_connection ->fetchAssoc (
2381
+ $ this ->_connection ->select ()->from (
2382
+ ['url_rewrite ' => $ resource ->getTable ('url_rewrite ' )],
2383
+ ['request_path ' , 'store_id ' ]
2384
+ )->joinLeft (
2385
+ ['cpe ' => $ resource ->getTable ('catalog_product_entity ' )],
2386
+ "cpe.entity_id = url_rewrite.entity_id "
2387
+ )->where ('request_path IN (?) ' , array_keys ($ urlKeys ))
2388
+ ->where ('store_id IN (?) ' , $ storeId )
2389
+ ->where ('cpe.sku not in (?) ' , array_values ($ urlKeys ))
2390
+ );
2391
+ foreach ($ urlKeyDuplicates as $ entityData ) {
2392
+ $ rowNum = $ this ->rowNumbers [$ entityData ['store_id ' ]][$ entityData ['request_path ' ]];
2393
+ $ this ->addRowError (ValidatorInterface::ERROR_DUPLICATE_URL_KEY , $ rowNum );
2394
+ }
2395
+ }
2396
+ }
2397
+
2398
+ /**
2399
+ * Retrieve product rewrite suffix for store
2400
+ *
2401
+ * @param int $storeId
2402
+ * @return string
2403
+ */
2404
+ protected function getProductUrlSuffix ($ storeId = null )
2405
+ {
2406
+ if (!isset ($ this ->productUrlSuffix [$ storeId ])) {
2407
+ $ this ->productUrlSuffix [$ storeId ] = $ this ->scopeConfig ->getValue (
2408
+ \Magento \CatalogUrlRewrite \Model \ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX ,
2409
+ \Magento \Store \Model \ScopeInterface::SCOPE_STORE ,
2410
+ $ storeId
2411
+ );
2412
+ }
2413
+ return $ this ->productUrlSuffix [$ storeId ];
2414
+ }
2415
+
2416
+ /**
2417
+ * @param array $rowData
2418
+ * @return string
2419
+ */
2420
+ protected function getUrlKey ($ rowData )
2421
+ {
2422
+ if (!empty ($ rowData [self ::URL_KEY ])) {
2423
+ $ this ->productUrlKeys [$ rowData [self ::COL_SKU ]] = $ rowData [self ::URL_KEY ];
2424
+ }
2425
+ $ urlKey = !empty ($ this ->productUrlKeys [$ rowData [self ::COL_SKU ]])
2426
+ ? $ this ->productUrlKeys [$ rowData [self ::COL_SKU ]]
2427
+ : $ this ->productUrl ->formatUrlKey ($ rowData [self ::COL_NAME ]);
2428
+ return $ urlKey ;
2429
+ }
2430
+
2431
+ /**
2432
+ * @return Proxy\Product\ResourceModel
2433
+ */
2434
+ protected function getResource ()
2435
+ {
2436
+ if (!$ this ->_resource ) {
2437
+ $ this ->_resource = $ this ->_resourceFactory ->create ();
2438
+ }
2439
+ return $ this ->_resource ;
2440
+ }
2325
2441
}
0 commit comments