Skip to content

Commit d08ae59

Browse files
ENGCOM-4776: #21737 Duplicating product with translated url keys over multiple sto… #22178
- Merge Pull Request #22178 from yvechirko/magento2:#21737_Duplicating_product_url_keys - Merged commits: 1. 48b0ab8 2. 30b0f91 3. 4e15099
2 parents 1ffd8c5 + 4e15099 commit d08ae59

File tree

2 files changed

+120
-28
lines changed

2 files changed

+120
-28
lines changed

app/code/Magento/Catalog/Model/Product/Copier.php

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,9 @@ public function copy(Product $product)
7474
$duplicate->setUpdatedAt(null);
7575
$duplicate->setId(null);
7676
$duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
77-
7877
$this->copyConstructor->build($product, $duplicate);
79-
$isDuplicateSaved = false;
80-
do {
81-
$urlKey = $duplicate->getUrlKey();
82-
$urlKey = preg_match('/(.*)-(\d+)$/', $urlKey, $matches)
83-
? $matches[1] . '-' . ($matches[2] + 1)
84-
: $urlKey . '-1';
85-
$duplicate->setUrlKey($urlKey);
86-
$duplicate->setData('url_path', null);
87-
try {
88-
$duplicate->save();
89-
$isDuplicateSaved = true;
90-
} catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
91-
}
92-
} while (!$isDuplicateSaved);
78+
$this->setDefaultUrl($product, $duplicate);
79+
$this->setStoresUrl($product, $duplicate);
9380
$this->getOptionRepository()->duplicate($product, $duplicate);
9481
$product->getResource()->duplicate(
9582
$product->getData($metadata->getLinkField()),
@@ -98,6 +85,80 @@ public function copy(Product $product)
9885
return $duplicate;
9986
}
10087

88+
/**
89+
* Set default URL.
90+
*
91+
* @param Product $product
92+
* @param Product $duplicate
93+
* @return void
94+
*/
95+
private function setDefaultUrl(Product $product, Product $duplicate) : void
96+
{
97+
$duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
98+
$resource = $product->getResource();
99+
$attribute = $resource->getAttribute('url_key');
100+
$productId = $product->getId();
101+
$urlKey = $resource->getAttributeRawValue($productId, 'url_key', \Magento\Store\Model\Store::DEFAULT_STORE_ID);
102+
do {
103+
$urlKey = $this->modifyUrl($urlKey);
104+
$duplicate->setUrlKey($urlKey);
105+
} while (!$attribute->getEntity()->checkAttributeUniqueValue($attribute, $duplicate));
106+
$duplicate->setData('url_path', null);
107+
$duplicate->save();
108+
}
109+
110+
/**
111+
* Set URL for each store.
112+
*
113+
* @param Product $product
114+
* @param Product $duplicate
115+
* @return void
116+
*/
117+
private function setStoresUrl(Product $product, Product $duplicate) : void
118+
{
119+
$storeIds = $duplicate->getStoreIds();
120+
$productId = $product->getId();
121+
$productResource = $product->getResource();
122+
$defaultUrlKey = $productResource->getAttributeRawValue(
123+
$productId,
124+
'url_key',
125+
\Magento\Store\Model\Store::DEFAULT_STORE_ID
126+
);
127+
$duplicate->setData('save_rewrites_history', false);
128+
foreach ($storeIds as $storeId) {
129+
$isDuplicateSaved = false;
130+
$duplicate->setStoreId($storeId);
131+
$urlKey = $productResource->getAttributeRawValue($productId, 'url_key', $storeId);
132+
if ($urlKey === $defaultUrlKey) {
133+
continue;
134+
}
135+
do {
136+
$urlKey = $this->modifyUrl($urlKey);
137+
$duplicate->setUrlKey($urlKey);
138+
$duplicate->setData('url_path', null);
139+
try {
140+
$duplicate->save();
141+
$isDuplicateSaved = true;
142+
} catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
143+
}
144+
} while (!$isDuplicateSaved);
145+
}
146+
$duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
147+
}
148+
149+
/**
150+
* Modify URL key.
151+
*
152+
* @param string $urlKey
153+
* @return string
154+
*/
155+
private function modifyUrl(string $urlKey) : string
156+
{
157+
return preg_match('/(.*)-(\d+)$/', $urlKey, $matches)
158+
? $matches[1] . '-' . ($matches[2] + 1)
159+
: $urlKey . '-1';
160+
}
161+
101162
/**
102163
* Returns product option repository.
103164
*

app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,44 @@ public function testCopy()
103103
['linkField', null, '1'],
104104
]);
105105

106-
$resourceMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class);
107-
$this->productMock->expects($this->once())->method('getResource')->will($this->returnValue($resourceMock));
106+
$entityMock = $this->getMockForAbstractClass(
107+
\Magento\Eav\Model\Entity\AbstractEntity::class,
108+
[],
109+
'',
110+
false,
111+
true,
112+
true,
113+
['checkAttributeUniqueValue']
114+
);
115+
$entityMock->expects($this->any())
116+
->method('checkAttributeUniqueValue')
117+
->willReturn(true);
118+
119+
$attributeMock = $this->getMockForAbstractClass(
120+
\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
121+
[],
122+
'',
123+
false,
124+
true,
125+
true,
126+
['getEntity']
127+
);
128+
$attributeMock->expects($this->any())
129+
->method('getEntity')
130+
->willReturn($entityMock);
131+
132+
$resourceMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product::class)
133+
->disableOriginalConstructor()
134+
->setMethods(['getAttributeRawValue', 'duplicate', 'getAttribute'])
135+
->getMock();
136+
$resourceMock->expects($this->any())
137+
->method('getAttributeRawValue')
138+
->willReturn('urk-key-1');
139+
$resourceMock->expects($this->any())
140+
->method('getAttribute')
141+
->willReturn($attributeMock);
142+
143+
$this->productMock->expects($this->any())->method('getResource')->will($this->returnValue($resourceMock));
108144

109145
$duplicateMock = $this->createPartialMock(
110146
Product::class,
@@ -119,11 +155,11 @@ public function testCopy()
119155
'setCreatedAt',
120156
'setUpdatedAt',
121157
'setId',
122-
'setStoreId',
123158
'getEntityId',
124159
'save',
125160
'setUrlKey',
126-
'getUrlKey',
161+
'setStoreId',
162+
'getStoreIds',
127163
]
128164
);
129165
$this->productFactoryMock->expects($this->once())->method('create')->will($this->returnValue($duplicateMock));
@@ -138,27 +174,22 @@ public function testCopy()
138174
)->with(
139175
\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED
140176
);
177+
$duplicateMock->expects($this->atLeastOnce())->method('setStoreId');
141178
$duplicateMock->expects($this->once())->method('setCreatedAt')->with(null);
142179
$duplicateMock->expects($this->once())->method('setUpdatedAt')->with(null);
143180
$duplicateMock->expects($this->once())->method('setId')->with(null);
144-
$duplicateMock->expects(
145-
$this->once()
146-
)->method(
147-
'setStoreId'
148-
)->with(
149-
\Magento\Store\Model\Store::DEFAULT_STORE_ID
150-
);
181+
$duplicateMock->expects($this->atLeastOnce())->method('getStoreIds')->willReturn([]);
151182
$duplicateMock->expects($this->atLeastOnce())->method('setData')->willReturn($duplicateMock);
152183
$this->copyConstructorMock->expects($this->once())->method('build')->with($this->productMock, $duplicateMock);
153-
$duplicateMock->expects($this->once())->method('getUrlKey')->willReturn('urk-key-1');
154184
$duplicateMock->expects($this->once())->method('setUrlKey')->with('urk-key-2')->willReturn($duplicateMock);
155185
$duplicateMock->expects($this->once())->method('save');
156186

157187
$this->metadata->expects($this->any())->method('getLinkField')->willReturn('linkField');
158188

159189
$duplicateMock->expects($this->any())->method('getData')->willReturnMap([
160190
['linkField', null, '2'],
161-
]); $this->optionRepositoryMock->expects($this->once())
191+
]);
192+
$this->optionRepositoryMock->expects($this->once())
162193
->method('duplicate')
163194
->with($this->productMock, $duplicateMock);
164195
$resourceMock->expects($this->once())->method('duplicate')->with(1, 2);

0 commit comments

Comments
 (0)