Skip to content

Commit a42cd33

Browse files
committed
MAGETWO-95122: [Magento Cloud] Default value for category URL path does not save
1 parent a72f59b commit a42cd33

File tree

5 files changed

+233
-20
lines changed

5 files changed

+233
-20
lines changed

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
use Magento\Catalog\Api\CategoryRepositoryInterface;
99
use Magento\Catalog\Model\Category;
1010

11+
/**
12+
* Class for generation category url_path.
13+
*/
1114
class CategoryUrlPathGenerator
1215
{
1316
/**
@@ -58,12 +61,13 @@ public function __construct(
5861
}
5962

6063
/**
61-
* Build category URL path
64+
* Build category URL path.
6265
*
6366
* @param \Magento\Catalog\Api\Data\CategoryInterface|\Magento\Framework\Model\AbstractModel $category
67+
* @param null|\Magento\Catalog\Api\Data\CategoryInterface|\Magento\Framework\Model\AbstractModel $parentCategory
6468
* @return string
6569
*/
66-
public function getUrlPath($category)
70+
public function getUrlPath($category, $parentCategory = null)
6771
{
6872
if (in_array($category->getParentId(), [Category::ROOT_CATEGORY_ID, Category::TREE_ROOT_ID])) {
6973
return '';
@@ -77,15 +81,18 @@ public function getUrlPath($category)
7781
return $category->getUrlPath();
7882
}
7983
if ($this->isNeedToGenerateUrlPathForParent($category)) {
80-
$parentPath = $this->getUrlPath(
81-
$this->categoryRepository->get($category->getParentId(), $category->getStoreId())
82-
);
84+
$parentCategory = $parentCategory ??
85+
$this->categoryRepository->get($category->getParentId(), $category->getStoreId());
86+
$parentPath = $this->getUrlPath($parentCategory);
8387
$path = $parentPath === '' ? $path : $parentPath . '/' . $path;
8488
}
89+
8590
return $path;
8691
}
8792

8893
/**
94+
* Define whether we should generate URL path for parent.
95+
*
8996
* @param \Magento\Catalog\Model\Category $category
9097
* @return bool
9198
*/

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

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
use Magento\Framework\Event\ObserverInterface;
1414
use Magento\Store\Model\Store;
1515

16+
/**
17+
* Class observer to initiate generation category url_path.
18+
*/
1619
class CategoryUrlPathAutogeneratorObserver implements ObserverInterface
1720
{
1821
/**
@@ -46,6 +49,8 @@ public function __construct(
4649
}
4750

4851
/**
52+
* Generate Category Url Path.
53+
*
4954
* @param \Magento\Framework\Event\Observer $observer
5055
* @return void
5156
* @throws \Magento\Framework\Exception\LocalizedException
@@ -57,21 +62,39 @@ public function execute(\Magento\Framework\Event\Observer $observer)
5762
$useDefaultAttribute = !$category->isObjectNew() && !empty($category->getData('use_default')['url_key']);
5863
if ($category->getUrlKey() !== false && !$useDefaultAttribute) {
5964
$resultUrlKey = $this->categoryUrlPathGenerator->getUrlKey($category);
60-
if (empty($resultUrlKey)) {
61-
throw new \Magento\Framework\Exception\LocalizedException(__('Invalid URL key'));
62-
}
63-
$category->setUrlKey($resultUrlKey)
64-
->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category));
65-
if (!$category->isObjectNew()) {
66-
$category->getResource()->saveAttribute($category, 'url_path');
67-
if ($category->dataHasChangedFor('url_path')) {
68-
$this->updateUrlPathForChildren($category);
69-
}
65+
$this->updateUrlKey($category, $resultUrlKey);
66+
} else if ($useDefaultAttribute) {
67+
$resultUrlKey = $category->formatUrlKey($category->getOrigData('name'));
68+
$this->updateUrlKey($category, $resultUrlKey);
69+
$category->setUrlKey(null)->setUrlPath(null);
70+
}
71+
}
72+
73+
/**
74+
* Update Url Key.
75+
*
76+
* @param Category $category
77+
* @param string $urlKey
78+
* @throws \Magento\Framework\Exception\LocalizedException
79+
*/
80+
private function updateUrlKey(Category $category, string $urlKey)
81+
{
82+
if (empty($urlKey)) {
83+
throw new \Magento\Framework\Exception\LocalizedException(__('Invalid URL key'));
84+
}
85+
$category->setUrlKey($urlKey)
86+
->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category));
87+
if (!$category->isObjectNew()) {
88+
$category->getResource()->saveAttribute($category, 'url_path');
89+
if ($category->dataHasChangedFor('url_path')) {
90+
$this->updateUrlPathForChildren($category);
7091
}
7192
}
7293
}
7394

7495
/**
96+
* Update URL path for children.
97+
*
7598
* @param Category $category
7699
* @return void
77100
*/
@@ -94,8 +117,13 @@ protected function updateUrlPathForChildren(Category $category)
94117
}
95118
} else {
96119
foreach ($children as $child) {
120+
/** @var Category $child */
97121
$child->setStoreId($category->getStoreId());
98-
$this->updateUrlPathForCategory($child);
122+
if ($child->getParentId() === $category->getId()) {
123+
$this->updateUrlPathForCategory($child, $category);
124+
} else {
125+
$this->updateUrlPathForCategory($child);
126+
}
99127
}
100128
}
101129
}
@@ -112,13 +140,16 @@ protected function isGlobalScope($storeId)
112140
}
113141

114142
/**
143+
* Update URL path for category.
144+
*
115145
* @param Category $category
146+
* @param Category|null $parentCategory
116147
* @return void
117148
*/
118-
protected function updateUrlPathForCategory(Category $category)
149+
protected function updateUrlPathForCategory(Category $category, Category $parentCategory = null)
119150
{
120151
$category->unsUrlPath();
121-
$category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category));
152+
$category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category, $parentCategory));
122153
$category->getResource()->saveAttribute($category, 'url_path');
123154
}
124155
}

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,61 @@ public function testGetUrlPathWithParent(
157157
$this->assertEquals($result, $this->categoryUrlPathGenerator->getUrlPath($this->category));
158158
}
159159

160+
/**
161+
* @return array
162+
*/
163+
public function getUrlPathWithParentCategoryDataProvider(): array
164+
{
165+
$requireGenerationLevel = CategoryUrlPathGenerator::MINIMAL_CATEGORY_LEVEL_FOR_PROCESSING;
166+
$noGenerationLevel = CategoryUrlPathGenerator::MINIMAL_CATEGORY_LEVEL_FOR_PROCESSING - 1;
167+
return [
168+
[13, 'url-key', false, $requireGenerationLevel, 10, 'parent-path', 'parent-path/url-key'],
169+
[13, 'url-key', false, $requireGenerationLevel, Category::TREE_ROOT_ID, null, 'url-key'],
170+
[13, 'url-key', true, $noGenerationLevel, Category::TREE_ROOT_ID, null, 'url-key'],
171+
];
172+
}
173+
174+
/**
175+
* Test receiving Url Path when parent category is presented.
176+
*
177+
* @param int $parentId
178+
* @param string $urlKey
179+
* @param bool $isCategoryNew
180+
* @param bool $level
181+
* @param int $parentCategoryParentId
182+
* @param null|string $parentUrlPath
183+
* @param string $result
184+
* @dataProvider getUrlPathWithParentCategoryDataProvider
185+
*/
186+
public function testGetUrlPathWithParentCategory(
187+
int $parentId,
188+
string $urlKey,
189+
bool $isCategoryNew,
190+
bool $level,
191+
int $parentCategoryParentId,
192+
$parentUrlPath,
193+
string $result
194+
) {
195+
$urlPath = null;
196+
$this->category->expects($this->any())->method('getParentId')->willReturn($parentId);
197+
$this->category->expects($this->any())->method('getLevel')->willReturn($level);
198+
$this->category->expects($this->any())->method('getUrlPath')->willReturn($urlPath);
199+
$this->category->expects($this->any())->method('getUrlKey')->willReturn($urlKey);
200+
$this->category->expects($this->any())->method('isObjectNew')->willReturn($isCategoryNew);
201+
202+
$methods = ['getUrlPath', 'getParentId'];
203+
$parentCategoryMock = $this->createPartialMock(\Magento\Catalog\Model\Category::class, $methods);
204+
$parentCategoryMock->expects($this->any())->method('getParentId')->willReturn($parentCategoryParentId);
205+
$parentCategoryMock->expects($this->any())->method('getUrlPath')->willReturn($parentUrlPath);
206+
207+
$this->categoryRepository->expects($this->any())
208+
->method('get')
209+
->with($parentCategoryParentId)
210+
->willReturn($parentCategoryMock);
211+
212+
$this->assertEquals($result, $this->categoryUrlPathGenerator->getUrlPath($this->category, $parentCategoryMock));
213+
}
214+
160215
/**
161216
* @return array
162217
*/

app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ protected function setUp()
4949
'getResource',
5050
'getUrlKey',
5151
'getStoreId',
52-
'getData'
52+
'getData',
53+
'getOrigData',
54+
'formatUrlKey',
5355
]);
5456
$this->category->expects($this->any())->method('getResource')->willReturn($this->categoryResource);
5557
$this->observer->expects($this->any())->method('getEvent')->willReturnSelf();
@@ -109,7 +111,35 @@ public function testExecuteWithException()
109111
$this->categoryUrlPathGenerator->expects($this->once())
110112
->method('getUrlKey')
111113
->with($this->category)
112-
->willReturn(null);
114+
->willReturn('');
115+
$this->categoryUrlPathAutogeneratorObserver->execute($this->observer);
116+
}
117+
118+
/**
119+
* Test execute method when option use default url key is true.
120+
*/
121+
public function testExecuteWithUseDefault()
122+
{
123+
$categoryName = 'test';
124+
$categoryData = ['url_key' => 1];
125+
$this->category->expects($this->once())->method('getUrlKey')->willReturn($categoryName);
126+
$this->category->expects($this->atLeastOnce())
127+
->method('getData')
128+
->with('use_default')
129+
->willReturn($categoryData);
130+
$this->category->expects($this->once())->method('getOrigData')->with('name')->willReturn('some_name');
131+
$this->category->expects($this->once())->method('formatUrlKey')->with('some_name')->willReturn('url_key');
132+
$this->category->expects($this->any())->method('setUrlKey')
133+
->willReturnMap([
134+
['url_key', $this->category],
135+
[null, $this->category],
136+
]);
137+
$this->category->expects($this->any())->method('setUrlPath')
138+
->willReturnMap([
139+
['url_path', $this->category],
140+
[null, $this->category],
141+
]);
142+
113143
$this->categoryUrlPathAutogeneratorObserver->execute($this->observer);
114144
}
115145

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

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
/**
1616
* @magentoAppArea adminhtml
17+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1718
*/
1819
class CategoryUrlRewriteGeneratorTest extends \PHPUnit\Framework\TestCase
1920
{
@@ -263,4 +264,93 @@ protected function assertResults($expected, $actual)
263264
);
264265
}
265266
}
267+
268+
/**
269+
* Get all actual url paths.
270+
*
271+
* @param array $filter
272+
* @return array
273+
*/
274+
private function getActualUrlPaths(array $filter)
275+
{
276+
/** @var \Magento\UrlRewrite\Model\UrlFinderInterface $urlFinder */
277+
$urlFinder = $this->objectManager->get(\Magento\UrlRewrite\Model\UrlFinderInterface::class);
278+
$actualResults = [];
279+
foreach ($urlFinder->findAllByData($filter) as $url) {
280+
$actualResults[] = [
281+
$url->getRequestPath(),
282+
$url->getTargetPath(),
283+
$url->getStoreId(),
284+
];
285+
}
286+
287+
return $actualResults;
288+
}
289+
290+
/**
291+
* Test getting url path.
292+
*
293+
* @magentoDataFixture Magento/Store/_files/second_store.php
294+
* @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php
295+
* @magentoDbIsolation enabled
296+
* @magentoAppIsolation enabled
297+
*/
298+
public function testGetUrlPath()
299+
{
300+
/** @var \Magento\Catalog\Api\CategoryRepositoryInterface $repository */
301+
$repository = $this->objectManager->get(\Magento\Catalog\Api\CategoryRepositoryInterface::class);
302+
303+
/** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */
304+
$storeRepository = $this->objectManager->get(\Magento\Store\Api\StoreRepositoryInterface::class);
305+
$storeId = $storeRepository->get('fixture_second_store')->getId();
306+
307+
$storeManager = $this->objectManager->get(\Magento\Store\Model\StoreManagerInterface::class);
308+
$store = $storeManager->getStore($storeId);
309+
$storeManager->setCurrentStore($store->getCode());
310+
311+
$categoryFilter = [
312+
UrlRewrite::ENTITY_TYPE => CategoryUrlRewriteGenerator::ENTITY_TYPE,
313+
UrlRewrite::ENTITY_ID => [5],
314+
];
315+
316+
$category = $repository->get(5);
317+
$category->addData(
318+
[
319+
'use_default' => [
320+
'url_key' => 0,
321+
],
322+
'url_key_create_redirect' => 0,
323+
'url_key' => 'url-key',
324+
]);
325+
$category->setStoreId($storeId);
326+
$repository->save($category);
327+
328+
$actualResults = $this->getActualUrlPaths($categoryFilter);
329+
$categoryExpectedResult = [
330+
['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 1],
331+
['category-1/category-1-1/url-key.html', 'catalog/category/view/id/5', 2],
332+
];
333+
334+
$this->assertResults($categoryExpectedResult, $actualResults);
335+
336+
$category = $repository->get(5);
337+
338+
$category->addData(
339+
[
340+
'use_default' => [
341+
'url_key' => 1,
342+
],
343+
'url_key' => '',
344+
]);
345+
346+
$repository->save($category);
347+
348+
$actualResults = $this->getActualUrlPaths($categoryFilter);
349+
$categoryExpectedResult = [
350+
['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 1],
351+
['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 2],
352+
];
353+
354+
$this->assertResults($categoryExpectedResult, $actualResults);
355+
}
266356
}

0 commit comments

Comments
 (0)