66
77namespace Magento \CatalogUrlRewrite \Observer ;
88
9+ use Magento \Catalog \Api \Data \ProductAttributeInterface ;
10+ use Magento \Catalog \Api \Data \ProductInterface ;
911use Magento \Catalog \Model \Category ;
1012use Magento \Catalog \Model \Product ;
1113use Magento \Catalog \Model \Product \Visibility ;
1921use Magento \CatalogUrlRewrite \Model \ProductUrlPathGenerator ;
2022use Magento \CatalogUrlRewrite \Model \ProductUrlRewriteGenerator ;
2123use Magento \CatalogUrlRewrite \Service \V1 \StoreViewService ;
24+ use Magento \Eav \Model \ResourceModel \AttributeValue ;
2225use Magento \Framework \App \Config \ScopeConfigInterface ;
2326use Magento \Framework \App \ObjectManager ;
2427use Magento \Framework \DataObject ;
4043/**
4144 * @SuppressWarnings(PHPMD.TooManyFields)
4245 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
46+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
4347 */
4448class AfterImportDataObserver implements ObserverInterface
4549{
@@ -187,6 +191,16 @@ class AfterImportDataObserver implements ObserverInterface
187191 */
188192 private $ productCollectionFactory ;
189193
194+ /**
195+ * @var AttributeValue
196+ */
197+ private $ attributeValue ;
198+
199+ /**
200+ * @var null|array
201+ */
202+ private $ cachedValues = null ;
203+
190204 /**
191205 * @param ProductFactory $catalogProductFactory
192206 * @param ObjectRegistryFactory $objectRegistryFactory
@@ -200,6 +214,7 @@ class AfterImportDataObserver implements ObserverInterface
200214 * @param CategoryCollectionFactory|null $categoryCollectionFactory
201215 * @param ScopeConfigInterface|null $scopeConfig
202216 * @param CollectionFactory|null $collectionFactory
217+ * @param AttributeValue|null $attributeValue
203218 * @SuppressWarnings(PHPMD.ExcessiveParameterList)
204219 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
205220 */
@@ -215,7 +230,8 @@ public function __construct(
215230 MergeDataProviderFactory $ mergeDataProviderFactory = null ,
216231 CategoryCollectionFactory $ categoryCollectionFactory = null ,
217232 ScopeConfigInterface $ scopeConfig = null ,
218- CollectionFactory $ collectionFactory = null
233+ CollectionFactory $ collectionFactory = null ,
234+ AttributeValue $ attributeValue = null
219235 ) {
220236 $ this ->urlPersist = $ urlPersist ;
221237 $ this ->catalogProductFactory = $ catalogProductFactory ;
@@ -234,6 +250,8 @@ public function __construct(
234250 ObjectManager::getInstance ()->get (ScopeConfigInterface::class);
235251 $ this ->productCollectionFactory = $ collectionFactory ?:
236252 ObjectManager::getInstance ()->get (CollectionFactory::class);
253+ $ this ->attributeValue = $ attributeValue ?:
254+ ObjectManager::getInstance ()->get (AttributeValue::class);
237255 }
238256
239257 /**
@@ -343,7 +361,7 @@ private function isNeedToPopulateForUrlGeneration($rowData, $newSku, $oldSku): b
343361 || (array_key_exists (strtolower ($ rowData [ImportProduct::COL_SKU ] ?? '' ), $ oldSku )
344362 && !isset ($ rowData [self ::URL_KEY_ATTRIBUTE_CODE ])
345363 && $ this ->import ->getBehavior () === ImportExport::BEHAVIOR_APPEND )
346- )
364+ )
347365 && !isset ($ rowData ["categories " ])
348366 ) {
349367 return false ;
@@ -446,18 +464,90 @@ private function canonicalUrlRewriteGenerate(array $products)
446464 foreach ($ products as $ productId => $ productsByStores ) {
447465 foreach ($ productsByStores as $ storeId => $ product ) {
448466 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+ }
449474 $ urls [] = $ this ->urlRewriteFactory ->create ()
450475 ->setEntityType (ProductUrlRewriteGenerator::ENTITY_TYPE )
451476 ->setEntityId ($ productId )
452- ->setRequestPath ($ this -> productUrlPathGenerator -> getUrlPathWithSuffix ( $ product , $ storeId ) )
453- ->setTargetPath ($ this -> productUrlPathGenerator -> getCanonicalUrlPath ( $ product ) )
477+ ->setRequestPath ($ reqPath )
478+ ->setTargetPath ($ targetPath )
454479 ->setStoreId ($ storeId );
455480 }
456481 }
457482 }
458483 return $ urls ;
459484 }
460485
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+
461551 /**
462552 * Generate list based on categories.
463553 *
@@ -476,12 +566,18 @@ private function categoriesUrlRewriteGenerate(array $products): array
476566 continue ;
477567 }
478568 $ 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+ }
479575 $ urls [] = [
480576 $ this ->urlRewriteFactory ->create ()
481577 ->setEntityType (ProductUrlRewriteGenerator::ENTITY_TYPE )
482578 ->setEntityId ($ productId )
483579 ->setRequestPath ($ requestPath )
484- ->setTargetPath ($ this -> productUrlPathGenerator -> getCanonicalUrlPath ( $ product , $ category ) )
580+ ->setTargetPath ($ targetPath )
485581 ->setStoreId ($ storeId )
486582 ->setMetadata (['category_id ' => $ category ->getId ()])
487583 ];
@@ -570,6 +666,7 @@ private function generateForAutogenerated(UrlRewrite $url, ?Category $category,
570666 * @param Category|null $category
571667 * @param Product[] $products
572668 * @return UrlRewrite[]
669+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
573670 */
574671 private function generateForCustom (UrlRewrite $ url , ?Category $ category , array $ products ) : array
575672 {
@@ -580,6 +677,18 @@ private function generateForCustom(UrlRewrite $url, ?Category $category, array $
580677 $ targetPath = $ url ->getRedirectType ()
581678 ? $ this ->productUrlPathGenerator ->getUrlPathWithSuffix ($ product , $ storeId , $ category )
582679 : $ 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+ }
583692 if ($ url ->getRequestPath () === $ targetPath ) {
584693 return [];
585694 }
0 commit comments