Skip to content

Commit 8545fd8

Browse files
author
Alexander Akimov
authored
Merge pull request #1185 from magento-troll/MAGETWO-67087
[Troll] MAGETWO-67087: Saving category deletes url-rewrites for products in anchor categories
2 parents 0aa7656 + 1e9a3ec commit 8545fd8

File tree

8 files changed

+195
-13
lines changed

8 files changed

+195
-13
lines changed

app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function __construct(
4141
}
4242

4343
/**
44-
* Generate list based on categories
44+
* Generate product rewrites for anchor categories
4545
*
4646
* @param int $storeId
4747
* @param Product $product

app/code/Magento/CatalogUrlRewrite/Model/Product/CanonicalUrlRewriteGenerator.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function __construct(ProductUrlPathGenerator $productUrlPathGenerator, Ur
3030
}
3131

3232
/**
33-
* Generate list based on store view
33+
* Generate product rewrites without categories
3434
*
3535
* @param int $storeId
3636
* @param Product $product

app/code/Magento/CatalogUrlRewrite/Model/Product/CategoriesUrlRewriteGenerator.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function __construct(ProductUrlPathGenerator $productUrlPathGenerator, Ur
3131
}
3232

3333
/**
34-
* Generate list based on categories
34+
* Generate product rewrites with categories
3535
*
3636
* @param int $storeId
3737
* @param Product $product

app/code/Magento/CatalogUrlRewrite/Model/Product/CurrentUrlRewritesRegenerator.php

+55-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\CatalogUrlRewrite\Model\Product;
77

88
use Magento\Catalog\Model\Category;
9+
use Magento\Catalog\Model\CategoryRepository;
910
use Magento\Catalog\Model\Product;
1011
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
1112
use Magento\UrlRewrite\Model\OptionProvider;
@@ -56,19 +57,24 @@ class CurrentUrlRewritesRegenerator
5657
/** @var \Magento\UrlRewrite\Model\MergeDataProvider */
5758
private $mergeDataProviderPrototype;
5859

60+
/** @var CategoryRepository */
61+
private $categoryRepository;
62+
5963
/**
6064
* @param UrlFinderInterface $urlFinder
6165
* @param ProductUrlPathGenerator $productUrlPathGenerator
6266
* @param UrlRewriteFactory $urlRewriteFactory
6367
* @param UrlRewriteFinder|null $urlRewriteFinder
6468
* @param \Magento\UrlRewrite\Model\MergeDataProviderFactory|null $mergeDataProviderFactory
69+
* @param CategoryRepository|null $categoryRepository
6570
*/
6671
public function __construct(
6772
UrlFinderInterface $urlFinder,
6873
ProductUrlPathGenerator $productUrlPathGenerator,
6974
UrlRewriteFactory $urlRewriteFactory,
7075
UrlRewriteFinder $urlRewriteFinder = null,
71-
MergeDataProviderFactory $mergeDataProviderFactory = null
76+
MergeDataProviderFactory $mergeDataProviderFactory = null,
77+
CategoryRepository $categoryRepository = null
7278
) {
7379
$this->urlFinder = $urlFinder;
7480
$this->productUrlPathGenerator = $productUrlPathGenerator;
@@ -78,11 +84,12 @@ public function __construct(
7884
if (!isset($mergeDataProviderFactory)) {
7985
$mergeDataProviderFactory = ObjectManager::getInstance()->get(MergeDataProviderFactory::class);
8086
}
87+
$this->categoryRepository = $categoryRepository ?: ObjectManager::getInstance()->get(CategoryRepository::class);
8188
$this->mergeDataProviderPrototype = $mergeDataProviderFactory->create();
8289
}
8390

8491
/**
85-
* Generate list based on current rewrites
92+
* Generate product rewrites based on current rewrites without anchor categories
8693
*
8794
* @param int $storeId
8895
* @param Product $product
@@ -115,6 +122,52 @@ public function generate($storeId, Product $product, ObjectRegistry $productCate
115122
return $mergeDataProvider->getData();
116123
}
117124

125+
/**
126+
* Generate product rewrites for anchor categories based on current rewrites
127+
*
128+
* @param int $storeId
129+
* @param Product $product
130+
* @param ObjectRegistry $productCategories
131+
* @param int|null $rootCategoryId
132+
* @return UrlRewrite[]
133+
*/
134+
public function generateAnchor(
135+
$storeId,
136+
Product $product,
137+
ObjectRegistry $productCategories,
138+
$rootCategoryId = null
139+
) {
140+
$anchorCategoryIds = [];
141+
$mergeDataProvider = clone $this->mergeDataProviderPrototype;
142+
143+
$currentUrlRewrites = $this->urlRewriteFinder->findAllByData(
144+
$product->getEntityId(),
145+
$storeId,
146+
ProductUrlRewriteGenerator::ENTITY_TYPE,
147+
$rootCategoryId
148+
);
149+
150+
foreach ($productCategories->getList() as $productCategory) {
151+
$anchorCategoryIds = array_merge($productCategory->getAnchorsAbove(), $anchorCategoryIds);
152+
}
153+
154+
foreach ($currentUrlRewrites as $currentUrlRewrite) {
155+
$metadata = $currentUrlRewrite->getMetadata();
156+
if (isset($metadata['category_id']) && $metadata['category_id'] > 0) {
157+
$category = $this->categoryRepository->get($metadata['category_id'], $storeId);
158+
if (in_array($category->getId(), $anchorCategoryIds)) {
159+
$mergeDataProvider->merge(
160+
$currentUrlRewrite->getIsAutogenerated()
161+
? $this->generateForAutogenerated($currentUrlRewrite, $storeId, $category, $product)
162+
: $this->generateForCustom($currentUrlRewrite, $storeId, $category, $product)
163+
);
164+
}
165+
}
166+
}
167+
168+
return $mergeDataProvider->getData();
169+
}
170+
118171
/**
119172
* @param UrlRewrite $url
120173
* @param int $storeId

app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,14 @@ public function generateForSpecificStoreView($storeId, $productCategories, Produ
171171
$mergeDataProvider->merge(
172172
$this->anchorUrlRewriteGenerator->generate($storeId, $product, $productCategories)
173173
);
174-
174+
$mergeDataProvider->merge(
175+
$this->currentUrlRewritesRegenerator->generateAnchor(
176+
$storeId,
177+
$product,
178+
$productCategories,
179+
$rootCategoryId
180+
)
181+
);
175182
return $mergeDataProvider->getData();
176183
}
177184

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

+13-5
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ public function __construct(
8080
public function generateProductUrlRewrites(\Magento\Catalog\Model\Category $category)
8181
{
8282
$mergeDataProvider = clone $this->mergeDataProviderPrototype;
83-
$this->isSkippedProduct = [];
83+
$this->isSkippedProduct[$category->getEntityId()] = [];
8484
$saveRewriteHistory = $category->getData('save_rewrites_history');
8585
$storeId = $category->getStoreId();
8686
if ($category->getAffectedProductIds()) {
87-
$this->isSkippedProduct = $category->getAffectedProductIds();
87+
$this->isSkippedProduct[$category->getEntityId()] = $category->getAffectedProductIds();
8888
$collection = $this->productCollectionFactory->create()
8989
->setStoreId($storeId)
9090
->addIdFilter($category->getAffectedProductIds())
@@ -137,17 +137,25 @@ public function getCategoryProductsUrlRewrites(
137137
$rootCategoryId = null
138138
) {
139139
$mergeDataProvider = clone $this->mergeDataProviderPrototype;
140+
140141
/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection */
141-
$productCollection = $category->getProductCollection()
142+
$productCollection = $this->productCollectionFactory->create();
143+
144+
$productCollection->addCategoriesFilter(['eq' => [$category->getEntityId()]])
145+
->setStoreId($storeId)
142146
->addAttributeToSelect('name')
143147
->addAttributeToSelect('visibility')
144148
->addAttributeToSelect('url_key')
145149
->addAttributeToSelect('url_path');
150+
146151
foreach ($productCollection as $product) {
147-
if (in_array($product->getId(), $this->isSkippedProduct)) {
152+
if (
153+
isset($this->isSkippedProduct[$category->getEntityId()]) &&
154+
in_array($product->getId(), $this->isSkippedProduct[$category->getEntityId()])
155+
) {
148156
continue;
149157
}
150-
$this->isSkippedProduct[] = $product->getId();
158+
$this->isSkippedProduct[$category->getEntityId()][] = $product->getId();
151159
$product->setStoreId($storeId);
152160
$product->setData('save_rewrites_history', $saveRewriteHistory);
153161
$mergeDataProvider->merge(

app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ public function testGenerationForGlobalScope()
137137
->setStoreId(3);
138138
$this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
139139
->will($this->returnValue([$current]));
140+
$this->currentUrlRewritesRegenerator->expects($this->any())->method('generateAnchor')
141+
->will($this->returnValue([$current]));
140142
$anchorCategories = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite([], $this->serializer);
141143
$anchorCategories->setRequestPath('category-4')
142144
->setStoreId(4);
@@ -178,6 +180,8 @@ public function testGenerationForSpecificStore()
178180
->will($this->returnValue([]));
179181
$this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
180182
->will($this->returnValue([]));
183+
$this->currentUrlRewritesRegenerator->expects($this->any())->method('generateAnchor')
184+
->will($this->returnValue([]));
181185
$this->anchorUrlRewriteGenerator->expects($this->any())->method('generate')
182186
->will($this->returnValue([]));
183187

dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php

+112-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use Magento\UrlRewrite\Model\OptionProvider;
1212
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
13+
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
1314

1415
/**
1516
* @magentoAppArea adminhtml
@@ -25,7 +26,7 @@ protected function setUp()
2526
}
2627

2728
/**
28-
* @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php
29+
* @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories_with_products.php
2930
* @magentoDbIsolation enabled
3031
* @magentoAppIsolation enabled
3132
*/
@@ -50,11 +51,56 @@ public function testGenerateUrlRewritesWithoutSaveHistory()
5051
];
5152

5253
$this->assertResults($categoryExpectedResult, $actualResults);
54+
55+
/** @var \Magento\Catalog\Model\ProductRepository $productRepository */
56+
$productRepository = $this->objectManager->create(\Magento\Catalog\Model\ProductRepository::class);
57+
$product = $productRepository->get('12345');
58+
$productForTest = $product->getId();
59+
60+
$productFilter = [
61+
UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE,
62+
UrlRewrite::ENTITY_ID => [$productForTest]
63+
];
64+
$actualResults = $this->getActualResults($productFilter);
65+
$productExpectedResult = [
66+
[
67+
'simple-product-two.html',
68+
'catalog/product/view/id/' . $productForTest,
69+
1,
70+
0
71+
],
72+
[
73+
'new-url/category-1-1/category-1-1-1/simple-product-two.html',
74+
'catalog/product/view/id/' . $productForTest . '/category/5',
75+
1,
76+
0
77+
],
78+
[
79+
'new-url/simple-product-two.html',
80+
'catalog/product/view/id/' . $productForTest . '/category/3',
81+
1,
82+
0
83+
],
84+
[
85+
'new-url/category-1-1/simple-product-two.html',
86+
'catalog/product/view/id/' . $productForTest . '/category/4',
87+
1,
88+
0
89+
],
90+
[
91+
'/simple-product-two.html',
92+
'catalog/product/view/id/' . $productForTest . '/category/2',
93+
1,
94+
0
95+
]
96+
];
97+
98+
$this->assertResults($productExpectedResult, $actualResults);
5399
}
54100

55101
/**
56102
* @magentoDbIsolation enabled
57-
* @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php
103+
* @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories_with_products.php
58104
* @magentoAppIsolation enabled
59105
*/
60106
public function testGenerateUrlRewritesWithSaveHistory()
@@ -86,6 +132,69 @@ public function testGenerateUrlRewritesWithSaveHistory()
86132
];
87133

88134
$this->assertResults($categoryExpectedResult, $actualResults);
135+
136+
/** @var \Magento\Catalog\Model\ProductRepository $productRepository */
137+
$productRepository = $this->objectManager->create(\Magento\Catalog\Model\ProductRepository::class);
138+
$product = $productRepository->get('12345');
139+
$productForTest = $product->getId();
140+
141+
$productFilter = [
142+
UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE,
143+
UrlRewrite::ENTITY_ID => [$productForTest]
144+
];
145+
$actualResults = $this->getActualResults($productFilter);
146+
$productExpectedResult = [
147+
[
148+
'simple-product-two.html',
149+
'catalog/product/view/id/' . $productForTest,
150+
1,
151+
0
152+
],
153+
[
154+
'new-url/category-1-1/category-1-1-1/simple-product-two.html',
155+
'catalog/product/view/id/' . $productForTest . '/category/5',
156+
1,
157+
0
158+
],
159+
[
160+
'category-1/category-1-1/category-1-1-1/simple-product-two.html',
161+
'new-url/category-1-1/category-1-1-1/simple-product-two.html',
162+
0,
163+
OptionProvider::PERMANENT
164+
],
165+
[
166+
'new-url/simple-product-two.html',
167+
'catalog/product/view/id/' . $productForTest . '/category/3',
168+
1,
169+
0
170+
],
171+
[
172+
'new-url/category-1-1/simple-product-two.html',
173+
'catalog/product/view/id/' . $productForTest . '/category/4',
174+
1,
175+
0
176+
],
177+
[
178+
'/simple-product-two.html',
179+
'catalog/product/view/id/' . $productForTest . '/category/2',
180+
1,
181+
0
182+
],
183+
[
184+
'category-1/simple-product-two.html',
185+
'new-url/simple-product-two.html',
186+
0,
187+
OptionProvider::PERMANENT
188+
],
189+
[
190+
'category-1/category-1-1/simple-product-two.html',
191+
'new-url/category-1-1/simple-product-two.html',
192+
0,
193+
OptionProvider::PERMANENT
194+
],
195+
];
196+
197+
$this->assertResults($productExpectedResult, $actualResults);
89198
}
90199

91200
/**
@@ -145,6 +254,7 @@ protected function getActualResults(array $filter)
145254
*/
146255
protected function assertResults($expected, $actual)
147256
{
257+
$this->assertEquals(count($expected), count($actual), 'Number of rewrites does not match');
148258
foreach ($expected as $row) {
149259
$this->assertContains(
150260
$row,

0 commit comments

Comments
 (0)