6
6
7
7
namespace Magento \CatalogUrlRewrite \Observer ;
8
8
9
+ use Magento \Catalog \Api \Data \ProductAttributeInterface ;
10
+ use Magento \Catalog \Api \Data \ProductInterface ;
9
11
use Magento \Catalog \Model \Category ;
10
12
use Magento \Catalog \Model \Product ;
11
13
use Magento \Catalog \Model \Product \Visibility ;
19
21
use Magento \CatalogUrlRewrite \Model \ProductUrlPathGenerator ;
20
22
use Magento \CatalogUrlRewrite \Model \ProductUrlRewriteGenerator ;
21
23
use Magento \CatalogUrlRewrite \Service \V1 \StoreViewService ;
24
+ use Magento \Eav \Model \ResourceModel \AttributeValue ;
22
25
use Magento \Framework \App \Config \ScopeConfigInterface ;
23
26
use Magento \Framework \App \ObjectManager ;
24
27
use Magento \Framework \DataObject ;
40
43
/**
41
44
* @SuppressWarnings(PHPMD.TooManyFields)
42
45
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
46
+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
43
47
*/
44
48
class AfterImportDataObserver implements ObserverInterface
45
49
{
@@ -187,6 +191,16 @@ class AfterImportDataObserver implements ObserverInterface
187
191
*/
188
192
private $ productCollectionFactory ;
189
193
194
+ /**
195
+ * @var AttributeValue
196
+ */
197
+ private $ attributeValue ;
198
+
199
+ /**
200
+ * @var null|array
201
+ */
202
+ private $ cachedValues = null ;
203
+
190
204
/**
191
205
* @param ProductFactory $catalogProductFactory
192
206
* @param ObjectRegistryFactory $objectRegistryFactory
@@ -200,6 +214,7 @@ class AfterImportDataObserver implements ObserverInterface
200
214
* @param CategoryCollectionFactory|null $categoryCollectionFactory
201
215
* @param ScopeConfigInterface|null $scopeConfig
202
216
* @param CollectionFactory|null $collectionFactory
217
+ * @param AttributeValue|null $attributeValue
203
218
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
204
219
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
205
220
*/
@@ -215,7 +230,8 @@ public function __construct(
215
230
MergeDataProviderFactory $ mergeDataProviderFactory = null ,
216
231
CategoryCollectionFactory $ categoryCollectionFactory = null ,
217
232
ScopeConfigInterface $ scopeConfig = null ,
218
- CollectionFactory $ collectionFactory = null
233
+ CollectionFactory $ collectionFactory = null ,
234
+ AttributeValue $ attributeValue = null
219
235
) {
220
236
$ this ->urlPersist = $ urlPersist ;
221
237
$ this ->catalogProductFactory = $ catalogProductFactory ;
@@ -234,6 +250,8 @@ public function __construct(
234
250
ObjectManager::getInstance ()->get (ScopeConfigInterface::class);
235
251
$ this ->productCollectionFactory = $ collectionFactory ?:
236
252
ObjectManager::getInstance ()->get (CollectionFactory::class);
253
+ $ this ->attributeValue = $ attributeValue ?:
254
+ ObjectManager::getInstance ()->get (AttributeValue::class);
237
255
}
238
256
239
257
/**
@@ -343,7 +361,7 @@ private function isNeedToPopulateForUrlGeneration($rowData, $newSku, $oldSku): b
343
361
|| (array_key_exists (strtolower ($ rowData [ImportProduct::COL_SKU ] ?? '' ), $ oldSku )
344
362
&& !isset ($ rowData [self ::URL_KEY_ATTRIBUTE_CODE ])
345
363
&& $ this ->import ->getBehavior () === ImportExport::BEHAVIOR_APPEND )
346
- )
364
+ )
347
365
&& !isset ($ rowData ["categories " ])
348
366
) {
349
367
return false ;
@@ -446,18 +464,90 @@ private function canonicalUrlRewriteGenerate(array $products)
446
464
foreach ($ products as $ productId => $ productsByStores ) {
447
465
foreach ($ productsByStores as $ storeId => $ product ) {
448
466
if ($ this ->productUrlPathGenerator ->getUrlPath ($ product )) {
467
+ $ reqPath = $ this ->productUrlPathGenerator ->getUrlPathWithSuffix ($ product , $ storeId );
468
+ $ targetPath = $ this ->productUrlPathGenerator ->getCanonicalUrlPath ($ product );
469
+ if ((int ) $ storeId !== (int ) $ product ->getStoreId ()
470
+ && $ this ->isGlobalScope ($ product ->getStoreId ())) {
471
+ $ this ->initializeCacheForProducts ($ products );
472
+ $ reqPath = $ this ->getReqPath ((int )$ productId , (int )$ storeId , $ product );
473
+ }
449
474
$ urls [] = $ this ->urlRewriteFactory ->create ()
450
475
->setEntityType (ProductUrlRewriteGenerator::ENTITY_TYPE )
451
476
->setEntityId ($ productId )
452
- ->setRequestPath ($ this -> productUrlPathGenerator -> getUrlPathWithSuffix ( $ product , $ storeId ) )
453
- ->setTargetPath ($ this -> productUrlPathGenerator -> getCanonicalUrlPath ( $ product ) )
477
+ ->setRequestPath ($ reqPath )
478
+ ->setTargetPath ($ targetPath )
454
479
->setStoreId ($ storeId );
455
480
}
456
481
}
457
482
}
458
483
return $ urls ;
459
484
}
460
485
486
+ /**
487
+ * Initialization for cache with scop based values
488
+ *
489
+ * @param array $products
490
+ * @return void
491
+ */
492
+ private function initializeCacheForProducts (array $ products ) : void
493
+ {
494
+ if ($ this ->cachedValues === null ) {
495
+ $ this ->cachedValues = $ this ->getScopeBasedUrlKeyValues ($ products );
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Get request path for the selected scope
501
+ *
502
+ * @param int $productId
503
+ * @param int $storeId
504
+ * @param Product $product
505
+ * @param Category|null $category
506
+ * @return string
507
+ */
508
+ private function getReqPath (int $ productId , int $ storeId , Product $ product , ?Category $ category = null ) : string
509
+ {
510
+ $ reqPath = $ this ->productUrlPathGenerator ->getUrlPathWithSuffix ($ product , $ storeId , $ category );
511
+ if (!empty ($ this ->cachedValues ) && isset ($ this ->cachedValues [$ productId ][$ storeId ])) {
512
+ $ storeProduct = clone $ product ;
513
+ $ storeProduct ->setStoreId ($ storeId );
514
+ $ storeProduct ->setUrlKey ($ this ->cachedValues [$ productId ][$ storeId ]);
515
+ $ reqPath = $ this ->productUrlPathGenerator ->getUrlPathWithSuffix ($ storeProduct , $ storeId , $ category );
516
+ }
517
+ return $ reqPath ;
518
+ }
519
+
520
+ /**
521
+ * Get url key attribute values for the specified scope
522
+ *
523
+ * @param array $products
524
+ * @return array
525
+ */
526
+ private function getScopeBasedUrlKeyValues (array $ products ) : array
527
+ {
528
+ $ values = [];
529
+ $ productIds = [];
530
+ $ storeIds = [];
531
+ foreach ($ products as $ productId => $ productsByStores ) {
532
+ $ productIds [] = (int ) $ productId ;
533
+ foreach (array_keys ($ productsByStores ) as $ id ) {
534
+ $ storeIds [] = (int ) $ id ;
535
+ }
536
+ }
537
+ $ productIds = array_unique ($ productIds );
538
+ $ storeIds = array_unique ($ storeIds );
539
+ if (!empty ($ productIds ) && !empty ($ storeIds )) {
540
+ $ values = $ this ->attributeValue ->getValuesMultiple (
541
+ ProductInterface::class,
542
+ $ productIds ,
543
+ [ProductAttributeInterface::CODE_SEO_FIELD_URL_KEY ],
544
+ $ storeIds
545
+ );
546
+ }
547
+
548
+ return $ values ;
549
+ }
550
+
461
551
/**
462
552
* Generate list based on categories.
463
553
*
@@ -476,12 +566,18 @@ private function categoriesUrlRewriteGenerate(array $products): array
476
566
continue ;
477
567
}
478
568
$ requestPath = $ this ->productUrlPathGenerator ->getUrlPathWithSuffix ($ product , $ storeId , $ category );
569
+ $ targetPath = $ this ->productUrlPathGenerator ->getCanonicalUrlPath ($ product , $ category );
570
+ if ((int ) $ storeId !== (int ) $ product ->getStoreId ()
571
+ && $ this ->isGlobalScope ($ product ->getStoreId ())) {
572
+ $ this ->initializeCacheForProducts ($ products );
573
+ $ requestPath = $ this ->getReqPath ((int )$ productId , (int )$ storeId , $ product , $ category );
574
+ }
479
575
$ urls [] = [
480
576
$ this ->urlRewriteFactory ->create ()
481
577
->setEntityType (ProductUrlRewriteGenerator::ENTITY_TYPE )
482
578
->setEntityId ($ productId )
483
579
->setRequestPath ($ requestPath )
484
- ->setTargetPath ($ this -> productUrlPathGenerator -> getCanonicalUrlPath ( $ product , $ category ) )
580
+ ->setTargetPath ($ targetPath )
485
581
->setStoreId ($ storeId )
486
582
->setMetadata (['category_id ' => $ category ->getId ()])
487
583
];
@@ -570,6 +666,7 @@ private function generateForAutogenerated(UrlRewrite $url, ?Category $category,
570
666
* @param Category|null $category
571
667
* @param Product[] $products
572
668
* @return UrlRewrite[]
669
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
573
670
*/
574
671
private function generateForCustom (UrlRewrite $ url , ?Category $ category , array $ products ) : array
575
672
{
@@ -580,6 +677,18 @@ private function generateForCustom(UrlRewrite $url, ?Category $category, array $
580
677
$ targetPath = $ url ->getRedirectType ()
581
678
? $ this ->productUrlPathGenerator ->getUrlPathWithSuffix ($ product , $ storeId , $ category )
582
679
: $ url ->getTargetPath ();
680
+ if ((int ) $ storeId !== (int ) $ product ->getStoreId ()
681
+ && $ this ->isGlobalScope ($ product ->getStoreId ())) {
682
+ $ this ->initializeCacheForProducts ($ products );
683
+ if (!empty ($ this ->cachedValues ) && isset ($ this ->cachedValues [$ productId ][$ storeId ])) {
684
+ $ storeProduct = clone $ product ;
685
+ $ storeProduct ->setStoreId ($ storeId );
686
+ $ storeProduct ->setUrlKey ($ this ->cachedValues [$ productId ][$ storeId ]);
687
+ $ targetPath = $ url ->getRedirectType ()
688
+ ? $ this ->productUrlPathGenerator ->getUrlPathWithSuffix ($ storeProduct , $ storeId , $ category )
689
+ : $ url ->getTargetPath ();
690
+ }
691
+ }
583
692
if ($ url ->getRequestPath () === $ targetPath ) {
584
693
return [];
585
694
}
0 commit comments