Skip to content

Commit 780f33b

Browse files
committed
Merge remote-tracking branch 'origin/MC-32411' into 2.4-develop-pr21
2 parents 9c0da70 + 236ff0f commit 780f33b

File tree

3 files changed

+121
-83
lines changed

3 files changed

+121
-83
lines changed

app/code/Magento/ConfigurableProduct/Model/Plugin/ProductRepositorySave.php

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
*/
66
namespace Magento\ConfigurableProduct\Model\Plugin;
77

8-
use Magento\Catalog\Model\ProductFactory;
98
use Magento\Catalog\Api\Data\ProductInterface;
109
use Magento\Framework\Exception\InputException;
1110
use Magento\Catalog\Api\ProductRepositoryInterface;
12-
use Magento\Framework\Exception\CouldNotSaveException;
1311
use Magento\ConfigurableProduct\Api\Data\OptionInterface;
1412
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
1513
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
14+
use Magento\Framework\Exception\NoSuchEntityException;
1615

16+
/**
17+
* Plugin to validate product links of configurable product and reset configurable attributes
18+
*/
1719
class ProductRepositorySave
1820
{
1921
/**
@@ -22,46 +24,45 @@ class ProductRepositorySave
2224
private $productAttributeRepository;
2325

2426
/**
25-
* @var ProductFactory
27+
* @var ProductRepositoryInterface
2628
*/
27-
private $productFactory;
29+
private $productRepository;
2830

2931
/**
3032
* @param ProductAttributeRepositoryInterface $productAttributeRepository
31-
* @param ProductFactory $productFactory
33+
* @param ProductRepositoryInterface $productRepository
3234
*/
3335
public function __construct(
3436
ProductAttributeRepositoryInterface $productAttributeRepository,
35-
ProductFactory $productFactory
37+
ProductRepositoryInterface $productRepository
3638
) {
3739
$this->productAttributeRepository = $productAttributeRepository;
38-
$this->productFactory = $productFactory;
40+
$this->productRepository = $productRepository;
3941
}
4042

4143
/**
42-
* Validate product links and reset configurable attributes to configurable product
44+
* Validate product links of configurable product
4345
*
4446
* @param ProductRepositoryInterface $subject
45-
* @param ProductInterface $result
4647
* @param ProductInterface $product
4748
* @param bool $saveOptions
48-
* @return ProductInterface
49-
* @throws CouldNotSaveException
49+
* @return array
5050
* @throws InputException
51+
* @throws NoSuchEntityException
5152
*
5253
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
5354
*/
54-
public function afterSave(
55+
public function beforeSave(
5556
ProductRepositoryInterface $subject,
56-
ProductInterface $result,
5757
ProductInterface $product,
5858
$saveOptions = false
5959
) {
60+
$result[] = $product;
6061
if ($product->getTypeId() !== Configurable::TYPE_CODE) {
6162
return $result;
6263
}
6364

64-
$extensionAttributes = $result->getExtensionAttributes();
65+
$extensionAttributes = $product->getExtensionAttributes();
6566
if ($extensionAttributes === null) {
6667
return $result;
6768
}
@@ -81,23 +82,49 @@ public function afterSave(
8182
$attributeCodes[] = $attributeCode;
8283
}
8384
$this->validateProductLinks($attributeCodes, $configurableLinks);
85+
86+
return $result;
87+
}
88+
89+
/**
90+
* Reset configurable attributes to configurable product
91+
*
92+
* @param ProductRepositoryInterface $subject
93+
* @param ProductInterface $result
94+
* @param ProductInterface $product
95+
* @param bool $saveOptions
96+
* @return ProductInterface
97+
*
98+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
99+
*/
100+
public function afterSave(
101+
ProductRepositoryInterface $subject,
102+
ProductInterface $result,
103+
ProductInterface $product,
104+
$saveOptions = false
105+
) {
106+
if ($product->getTypeId() !== Configurable::TYPE_CODE) {
107+
return $result;
108+
}
84109
$result->getTypeInstance()->resetConfigurableAttributes($product);
85110

86111
return $result;
87112
}
88113

89114
/**
115+
* Validate product links
116+
*
90117
* @param array $attributeCodes
91118
* @param array $linkIds
92-
* @return $this
119+
* @return void
93120
* @throws InputException
121+
* @throws NoSuchEntityException
94122
*/
95123
private function validateProductLinks(array $attributeCodes, array $linkIds)
96124
{
97125
$valueMap = [];
98-
99126
foreach ($linkIds as $productId) {
100-
$variation = $this->productFactory->create()->load($productId);
127+
$variation = $this->productRepository->getById($productId);
101128
$valueKey = '';
102129
foreach ($attributeCodes as $attributeCode) {
103130
if (!$variation->getData($attributeCode)) {

app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/ProductRepositorySaveTest.php

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,26 @@
99
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
1010
use Magento\Catalog\Api\ProductRepositoryInterface;
1111
use Magento\Catalog\Model\Product;
12-
use Magento\Catalog\Model\ProductFactory;
1312
use Magento\ConfigurableProduct\Api\Data\OptionInterface;
1413
use Magento\ConfigurableProduct\Model\Plugin\ProductRepositorySave;
1514
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
1615
use Magento\ConfigurableProduct\Test\Unit\Model\Product\ProductExtensionAttributes;
1716
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
18-
use PHPUnit_Framework_MockObject_MockObject as MockObject;
17+
use PHPUnit\Framework\MockObject\MockObject;
18+
use PHPUnit\Framework\TestCase;
1919

2020
/**
21-
* Class ProductRepositorySaveTest
21+
* Test for ProductRepositorySave plugin
22+
*
2223
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2324
*/
24-
class ProductRepositorySaveTest extends \PHPUnit\Framework\TestCase
25+
class ProductRepositorySaveTest extends TestCase
2526
{
2627
/**
2728
* @var ProductAttributeRepositoryInterface|MockObject
2829
*/
2930
private $productAttributeRepository;
3031

31-
/**
32-
* @var ProductFactory|MockObject
33-
*/
34-
private $productFactory;
35-
3632
/**
3733
* @var Product|MockObject
3834
*/
@@ -68,15 +64,13 @@ class ProductRepositorySaveTest extends \PHPUnit\Framework\TestCase
6864
*/
6965
private $plugin;
7066

67+
/**
68+
* @inheritdoc
69+
*/
7170
protected function setUp()
7271
{
7372
$this->productAttributeRepository = $this->getMockForAbstractClass(ProductAttributeRepositoryInterface::class);
7473

75-
$this->productFactory = $this->getMockBuilder(ProductFactory::class)
76-
->disableOriginalConstructor()
77-
->setMethods(['create'])
78-
->getMock();
79-
8074
$this->product = $this->getMockBuilder(Product::class)
8175
->disableOriginalConstructor()
8276
->setMethods(['getTypeId', 'getExtensionAttributes'])
@@ -102,12 +96,15 @@ protected function setUp()
10296
ProductRepositorySave::class,
10397
[
10498
'productAttributeRepository' => $this->productAttributeRepository,
105-
'productFactory' => $this->productFactory
99+
'productRepository' => $this->productRepository
106100
]
107101
);
108102
}
109103

110-
public function testAfterSaveWhenProductIsSimple()
104+
/**
105+
* Validating the result after saving a configurable product
106+
*/
107+
public function testBeforeSaveWhenProductIsSimple()
111108
{
112109
$this->product->expects(static::once())
113110
->method('getTypeId')
@@ -116,18 +113,21 @@ public function testAfterSaveWhenProductIsSimple()
116113
->method('getExtensionAttributes');
117114

118115
$this->assertEquals(
119-
$this->result,
120-
$this->plugin->afterSave($this->productRepository, $this->result, $this->product)
116+
$this->product,
117+
$this->plugin->beforeSave($this->productRepository, $this->product)[0]
121118
);
122119
}
123120

124-
public function testAfterSaveWithoutOptions()
121+
/**
122+
* Test saving a configurable product without attribute options
123+
*/
124+
public function testBeforeSaveWithoutOptions()
125125
{
126126
$this->product->expects(static::once())
127127
->method('getTypeId')
128128
->willReturn(Configurable::TYPE_CODE);
129129

130-
$this->result->expects(static::once())
130+
$this->product->expects(static::once())
131131
->method('getExtensionAttributes')
132132
->willReturn($this->extensionAttributes);
133133

@@ -142,23 +142,25 @@ public function testAfterSaveWithoutOptions()
142142
->method('get');
143143

144144
$this->assertEquals(
145-
$this->result,
146-
$this->plugin->afterSave($this->productRepository, $this->result, $this->product)
145+
$this->product,
146+
$this->plugin->beforeSave($this->productRepository, $this->product)[0]
147147
);
148148
}
149149

150150
/**
151+
* Test saving a configurable product with same set of attribute values
152+
*
151153
* @expectedException \Magento\Framework\Exception\InputException
152154
* @expectedExceptionMessage Products "5" and "4" have the same set of attribute values.
153155
*/
154-
public function testAfterSaveWithLinks()
156+
public function testBeforeSaveWithLinks()
155157
{
156158
$links = [4, 5];
157159
$this->product->expects(static::once())
158160
->method('getTypeId')
159161
->willReturn(Configurable::TYPE_CODE);
160162

161-
$this->result->expects(static::once())
163+
$this->product->expects(static::once())
162164
->method('getExtensionAttributes')
163165
->willReturn($this->extensionAttributes);
164166
$this->extensionAttributes->expects(static::once())
@@ -173,27 +175,26 @@ public function testAfterSaveWithLinks()
173175

174176
$product = $this->getMockBuilder(Product::class)
175177
->disableOriginalConstructor()
176-
->setMethods(['load', 'getData', '__wakeup'])
178+
->setMethods(['getData', '__wakeup'])
177179
->getMock();
178180

179-
$this->productFactory->expects(static::exactly(2))
180-
->method('create')
181+
$this->productRepository->expects(static::exactly(2))
182+
->method('getById')
181183
->willReturn($product);
182184

183-
$product->expects(static::exactly(2))
184-
->method('load')
185-
->willReturnSelf();
186185
$product->expects(static::never())
187186
->method('getData');
188187

189-
$this->plugin->afterSave($this->productRepository, $this->result, $this->product);
188+
$this->plugin->beforeSave($this->productRepository, $this->product);
190189
}
191190

192191
/**
192+
* Test saving a configurable product with missing attribute
193+
*
193194
* @expectedException \Magento\Framework\Exception\InputException
194195
* @expectedExceptionMessage Product with id "4" does not contain required attribute "color".
195196
*/
196-
public function testAfterSaveWithLinksWithMissingAttribute()
197+
public function testBeforeSaveWithLinksWithMissingAttribute()
197198
{
198199
$simpleProductId = 4;
199200
$links = [$simpleProductId, 5];
@@ -208,7 +209,7 @@ public function testAfterSaveWithLinksWithMissingAttribute()
208209
->method('getTypeId')
209210
->willReturn(Configurable::TYPE_CODE);
210211

211-
$this->result->expects(static::once())
212+
$this->product->expects(static::once())
212213
->method('getExtensionAttributes')
213214
->willReturn($this->extensionAttributes);
214215
$this->extensionAttributes->expects(static::once())
@@ -228,29 +229,28 @@ public function testAfterSaveWithLinksWithMissingAttribute()
228229

229230
$product = $this->getMockBuilder(Product::class)
230231
->disableOriginalConstructor()
231-
->setMethods(['load', 'getData', '__wakeup'])
232+
->setMethods(['getData', '__wakeup'])
232233
->getMock();
233234

234-
$this->productFactory->expects(static::once())
235-
->method('create')
235+
$this->productRepository->expects(static::once())
236+
->method('getById')
236237
->willReturn($product);
237-
$product->expects(static::once())
238-
->method('load')
239-
->with($simpleProductId)
240-
->willReturnSelf();
238+
241239
$product->expects(static::once())
242240
->method('getData')
243241
->with($attributeCode)
244242
->willReturn(false);
245243

246-
$this->plugin->afterSave($this->productRepository, $this->result, $this->product);
244+
$this->plugin->beforeSave($this->productRepository, $this->product);
247245
}
248246

249247
/**
248+
* Test saving a configurable product with duplicate attributes
249+
*
250250
* @expectedException \Magento\Framework\Exception\InputException
251251
* @expectedExceptionMessage Products "5" and "4" have the same set of attribute values.
252252
*/
253-
public function testAfterSaveWithLinksWithDuplicateAttributes()
253+
public function testBeforeSaveWithLinksWithDuplicateAttributes()
254254
{
255255
$links = [4, 5];
256256
$attributeCode = 'color';
@@ -264,7 +264,7 @@ public function testAfterSaveWithLinksWithDuplicateAttributes()
264264
->method('getTypeId')
265265
->willReturn(Configurable::TYPE_CODE);
266266

267-
$this->result->expects(static::once())
267+
$this->product->expects(static::once())
268268
->method('getExtensionAttributes')
269269
->willReturn($this->extensionAttributes);
270270
$this->extensionAttributes->expects(static::once())
@@ -284,20 +284,18 @@ public function testAfterSaveWithLinksWithDuplicateAttributes()
284284

285285
$product = $this->getMockBuilder(Product::class)
286286
->disableOriginalConstructor()
287-
->setMethods(['load', 'getData', '__wakeup'])
287+
->setMethods(['getData', '__wakeup'])
288288
->getMock();
289289

290-
$this->productFactory->expects(static::exactly(2))
291-
->method('create')
290+
$this->productRepository->expects(static::exactly(2))
291+
->method('getById')
292292
->willReturn($product);
293-
$product->expects(static::exactly(2))
294-
->method('load')
295-
->willReturnSelf();
293+
296294
$product->expects(static::exactly(4))
297295
->method('getData')
298296
->with($attributeCode)
299297
->willReturn($attributeId);
300298

301-
$this->plugin->afterSave($this->productRepository, $this->result, $this->product);
299+
$this->plugin->beforeSave($this->productRepository, $this->product);
302300
}
303301
}

0 commit comments

Comments
 (0)