Skip to content

Commit d8a31d4

Browse files
authored
ENGCOM-7162: Fixed URL Rewrite addition/removal on product website add/remove #26999
2 parents 259e16d + 9e1298e commit d8a31d4

File tree

48 files changed

+1534
-236
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1534
-236
lines changed

app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,26 @@
55
*/
66
namespace Magento\CatalogUrlRewrite\Observer;
77

8+
use Magento\Catalog\Api\Data\ProductInterface;
89
use Magento\Catalog\Model\Product;
10+
use Magento\Catalog\Model\Product\Visibility;
11+
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
12+
use Magento\CatalogUrlRewrite\Model\ProductScopeRewriteGenerator;
913
use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator;
1014
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
11-
use Magento\Framework\App\ObjectManager;
15+
use Magento\Framework\Event\Observer;
16+
use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException;
17+
use Magento\UrlRewrite\Model\Storage\DeleteEntitiesFromStores;
1218
use Magento\UrlRewrite\Model\UrlPersistInterface;
1319
use Magento\Framework\Event\ObserverInterface;
20+
use Magento\Store\Model\StoreManagerInterface;
1421

1522
/**
1623
* Class ProductProcessUrlRewriteSavingObserver
24+
*
25+
* Observer to update the Rewrite URLs for a product.
26+
* This observer is triggered on the save function when making changes
27+
* to the products website on the Product Edit page.
1728
*/
1829
class ProductProcessUrlRewriteSavingObserver implements ObserverInterface
1930
{
@@ -32,30 +43,62 @@ class ProductProcessUrlRewriteSavingObserver implements ObserverInterface
3243
*/
3344
private $productUrlPathGenerator;
3445

46+
/**
47+
* @var StoreManagerInterface
48+
*/
49+
private $storeManager;
50+
51+
/**
52+
* @var ProductScopeRewriteGenerator
53+
*/
54+
private $productScopeRewriteGenerator;
55+
56+
/**
57+
* @var DeleteEntitiesFromStores
58+
*/
59+
private $deleteEntitiesFromStores;
60+
61+
/**
62+
* @var CollectionFactory
63+
*/
64+
private $collectionFactory;
65+
3566
/**
3667
* @param ProductUrlRewriteGenerator $productUrlRewriteGenerator
3768
* @param UrlPersistInterface $urlPersist
38-
* @param ProductUrlPathGenerator|null $productUrlPathGenerator
69+
* @param ProductUrlPathGenerator $productUrlPathGenerator
70+
* @param StoreManagerInterface $storeManager
71+
* @param ProductScopeRewriteGenerator $productScopeRewriteGenerator
72+
* @param DeleteEntitiesFromStores $deleteEntitiesFromStores
73+
* @param CollectionFactory $collectionFactory
3974
*/
4075
public function __construct(
4176
ProductUrlRewriteGenerator $productUrlRewriteGenerator,
4277
UrlPersistInterface $urlPersist,
43-
ProductUrlPathGenerator $productUrlPathGenerator = null
78+
ProductUrlPathGenerator $productUrlPathGenerator,
79+
StoreManagerInterface $storeManager,
80+
ProductScopeRewriteGenerator $productScopeRewriteGenerator,
81+
DeleteEntitiesFromStores $deleteEntitiesFromStores,
82+
CollectionFactory $collectionFactory
4483
) {
4584
$this->productUrlRewriteGenerator = $productUrlRewriteGenerator;
4685
$this->urlPersist = $urlPersist;
47-
$this->productUrlPathGenerator = $productUrlPathGenerator ?: ObjectManager::getInstance()
48-
->get(ProductUrlPathGenerator::class);
86+
$this->productUrlPathGenerator = $productUrlPathGenerator;
87+
$this->storeManager = $storeManager;
88+
$this->productScopeRewriteGenerator = $productScopeRewriteGenerator;
89+
$this->deleteEntitiesFromStores = $deleteEntitiesFromStores;
90+
$this->collectionFactory = $collectionFactory;
4991
}
5092

5193
/**
5294
* Generate urls for UrlRewrite and save it in storage
5395
*
54-
* @param \Magento\Framework\Event\Observer $observer
96+
* @param Observer $observer
5597
* @return void
56-
* @throws \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException
98+
* @throws UrlAlreadyExistsException
99+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
57100
*/
58-
public function execute(\Magento\Framework\Event\Observer $observer)
101+
public function execute(Observer $observer)
59102
{
60103
/** @var Product $product */
61104
$product = $observer->getEvent()->getProduct();
@@ -65,11 +108,49 @@ public function execute(\Magento\Framework\Event\Observer $observer)
65108
|| $product->getIsChangedWebsites()
66109
|| $product->dataHasChangedFor('visibility')
67110
) {
68-
if ($product->isVisibleInSiteVisibility()) {
69-
$product->unsUrlPath();
70-
$product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product));
111+
//Refresh rewrite urls
112+
$product->unsUrlPath();
113+
$product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product));
114+
if (!empty($this->productUrlRewriteGenerator->generate($product))) {
71115
$this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product));
72116
}
117+
118+
$storeIdsToRemove = [];
119+
$productWebsiteMap = array_flip($product->getWebsiteIds());
120+
$storeVisibilities = $this->collectionFactory->create()
121+
->getAllAttributeValues(ProductInterface::VISIBILITY);
122+
if ($this->productScopeRewriteGenerator->isGlobalScope($product->getStoreId())) {
123+
//Remove any rewrite URLs for websites the product is not in, or is not visible in. Global Scope.
124+
foreach ($this->storeManager->getStores() as $store) {
125+
$websiteId = $store->getWebsiteId();
126+
$storeId = $store->getStoreId();
127+
if (!isset($productWebsiteMap[$websiteId])) {
128+
$storeIdsToRemove[] = $storeId;
129+
continue;
130+
}
131+
//Check the visibility of the product in each store.
132+
if (isset($storeVisibilities[$product->getId()][$storeId])
133+
&& ($storeVisibilities[$product->getId()][$storeId] === Visibility::VISIBILITY_NOT_VISIBLE)) {
134+
$storeIdsToRemove[] = $storeId;
135+
}
136+
}
137+
} else {
138+
//Only remove rewrite for current scope
139+
$websiteId = $product->getStore()->getWebsiteId();
140+
$storeId = $product->getStoreId();
141+
if (!isset($productWebsiteMap[$websiteId]) ||
142+
(isset($storeVisibilities[$product->getId()][$storeId])
143+
&& ($storeVisibilities[$product->getId()][$storeId] === Visibility::VISIBILITY_NOT_VISIBLE))) {
144+
$storeIdsToRemove[] = $storeId;
145+
}
146+
}
147+
if (count($storeIdsToRemove)) {
148+
$this->deleteEntitiesFromStores->execute(
149+
$storeIdsToRemove,
150+
[$product->getId()],
151+
ProductUrlRewriteGenerator::ENTITY_TYPE
152+
);
153+
}
73154
}
74155
}
75156
}

app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php

Lines changed: 0 additions & 104 deletions
This file was deleted.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogUrlRewrite\Plugin;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\Catalog\Model\Product\Action;
13+
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
14+
use Magento\Store\Api\StoreWebsiteRelationInterface;
15+
use Magento\Store\Model\Store;
16+
use Magento\UrlRewrite\Model\Storage\DeleteEntitiesFromStores;
17+
use Magento\UrlRewrite\Model\UrlPersistInterface;
18+
19+
/**
20+
* Class ProductProcessUrlRewriteRemovingPlugin
21+
*
22+
* Plugin to update the Rewrite URLs for a product.
23+
* This plugin is triggered by the product_action_attribute.website.update
24+
* consumer in response to Mass Action changes in the Admin Product Grid.
25+
*/
26+
class ProductProcessUrlRewriteRemovingPlugin
27+
{
28+
/**
29+
* @var ProductRepositoryInterface
30+
*/
31+
private $productRepository;
32+
33+
/**
34+
* @var StoreWebsiteRelationInterface
35+
*/
36+
private $storeWebsiteRelation;
37+
38+
/**
39+
* @var UrlPersistInterface
40+
*/
41+
private $urlPersist;
42+
43+
/**
44+
* @var ProductUrlRewriteGenerator
45+
*/
46+
private $productUrlRewriteGenerator;
47+
48+
/**
49+
* @var DeleteEntitiesFromStores
50+
*/
51+
private $deleteEntitiesFromStores;
52+
53+
/**
54+
* @param ProductRepositoryInterface $productRepository
55+
* @param StoreWebsiteRelationInterface $storeWebsiteRelation
56+
* @param UrlPersistInterface $urlPersist
57+
* @param ProductUrlRewriteGenerator $productUrlRewriteGenerator
58+
* @param DeleteEntitiesFromStores $deleteEntitiesFromStores
59+
*/
60+
public function __construct(
61+
ProductRepositoryInterface $productRepository,
62+
StoreWebsiteRelationInterface $storeWebsiteRelation,
63+
UrlPersistInterface $urlPersist,
64+
ProductUrlRewriteGenerator $productUrlRewriteGenerator,
65+
DeleteEntitiesFromStores $deleteEntitiesFromStores
66+
) {
67+
$this->productRepository = $productRepository;
68+
$this->storeWebsiteRelation = $storeWebsiteRelation;
69+
$this->urlPersist = $urlPersist;
70+
$this->productUrlRewriteGenerator = $productUrlRewriteGenerator;
71+
$this->deleteEntitiesFromStores = $deleteEntitiesFromStores;
72+
}
73+
74+
/**
75+
* Function afterUpdateWebsites
76+
*
77+
* @param Action $subject
78+
* @param void $result
79+
* @param array $productIds
80+
* @param array $websiteIds
81+
* @param string $type
82+
* @return void
83+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
84+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
85+
*/
86+
public function afterUpdateWebsites(
87+
Action $subject,
88+
$result,
89+
$productIds,
90+
$websiteIds,
91+
$type
92+
) {
93+
foreach ($productIds as $productId) {
94+
/* @var Product $product */
95+
$product = $this->productRepository->getById(
96+
$productId,
97+
false,
98+
Store::DEFAULT_STORE_ID,
99+
true
100+
);
101+
102+
// Refresh all existing URLs for the product
103+
if (!empty($this->productUrlRewriteGenerator->generate($product))) {
104+
if ($product->isVisibleInSiteVisibility()) {
105+
$this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product));
106+
}
107+
}
108+
}
109+
110+
$storeIdsToRemove = [];
111+
// Remove the URLs for products in $productIds array
112+
// from all stores that belong to websites in $websiteIds array
113+
if ($type === "remove" && $websiteIds && $productIds) {
114+
foreach ($websiteIds as $webId) {
115+
foreach ($this->storeWebsiteRelation->getStoreByWebsiteId($webId) as $storeid) {
116+
$storeIdsToRemove[] = $storeid;
117+
}
118+
}
119+
if (count($storeIdsToRemove)) {
120+
$this->deleteEntitiesFromStores->execute(
121+
$storeIdsToRemove,
122+
$productIds,
123+
ProductUrlRewriteGenerator::ENTITY_TYPE
124+
);
125+
}
126+
}
127+
}
128+
}

app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminCategoryWithRestrictedUrlKeyNotCreatedTest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<testCaseId value="MC-17515"/>
1818
<useCaseId value="MAGETWO-69825"/>
1919
<group value="CatalogUrlRewrite"/>
20+
<group value="urlRewrite"/>
2021
</annotations>
2122
<before>
2223
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>

0 commit comments

Comments
 (0)