Skip to content

Commit 4596c75

Browse files
author
Bohdan Korablov
committed
Merge remote-tracking branch 'mainline/2.2-develop' into MAGETWO-71922
2 parents 9228648 + 097f8af commit 4596c75

File tree

4 files changed

+273
-3
lines changed

4 files changed

+273
-3
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks;
1313
use Magento\Catalog\Model\Product\Link\Resolver as LinkResolver;
1414
use Magento\Framework\App\ObjectManager;
15+
use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper\AttributeFilter;
1516

1617
/**
1718
* @api
@@ -84,6 +85,11 @@ class Helper
8485
*/
8586
private $linkTypeProvider;
8687

88+
/**
89+
* @var AttributeFilter
90+
*/
91+
private $attributeFilter;
92+
8793
/**
8894
* Constructor
8995
*
@@ -97,6 +103,7 @@ class Helper
97103
* @param \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory|null $productLinkFactory
98104
* @param \Magento\Catalog\Api\ProductRepositoryInterface|null $productRepository
99105
* @param \Magento\Catalog\Model\Product\LinkTypeProvider|null $linkTypeProvider
106+
* @param AttributeFilter|null $attributeFilter
100107
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
101108
*/
102109
public function __construct(
@@ -109,7 +116,8 @@ public function __construct(
109116
\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory $customOptionFactory = null,
110117
\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory = null,
111118
\Magento\Catalog\Api\ProductRepositoryInterface $productRepository = null,
112-
\Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider = null
119+
\Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider = null,
120+
AttributeFilter $attributeFilter = null
113121
) {
114122
$this->request = $request;
115123
$this->storeManager = $storeManager;
@@ -125,6 +133,8 @@ public function __construct(
125133
->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
126134
$this->linkTypeProvider = $linkTypeProvider ?: \Magento\Framework\App\ObjectManager::getInstance()
127135
->get(\Magento\Catalog\Model\Product\LinkTypeProvider::class);
136+
$this->attributeFilter = $attributeFilter ?: \Magento\Framework\App\ObjectManager::getInstance()
137+
->get(AttributeFilter::class);
128138
}
129139

130140
/**
@@ -187,6 +197,11 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra
187197
$productOptions = [];
188198
}
189199
$productData['tier_price'] = isset($productData['tier_price']) ? $productData['tier_price'] : [];
200+
201+
$useDefaults = (array)$this->request->getPost('use_default', []);
202+
203+
$productData = $this->attributeFilter->prepareProductAttributes($product, $productData, $useDefaults);
204+
190205
$product->addData($productData);
191206

192207
if ($wasLockedMedia) {
@@ -196,8 +211,6 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra
196211
/**
197212
* Check "Use Default Value" checkboxes values
198213
*/
199-
$useDefaults = (array)$this->request->getPost('use_default', []);
200-
201214
foreach ($useDefaults as $attributeCode => $useDefaultState) {
202215
if ($useDefaultState) {
203216
$product->setData($attributeCode, null);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper;
7+
8+
use \Magento\Catalog\Model\Product;
9+
10+
/**
11+
* Class provides functionality to check and filter data came with product form.
12+
*
13+
* The main goal is to avoid database population with empty(null) attribute values.
14+
*/
15+
class AttributeFilter
16+
{
17+
/**
18+
* Method provides product data check and its further filtration.
19+
*
20+
* Filtration helps us to avoid unnecessary empty product data to be saved.
21+
* Empty data will be preserved only if user explicitly set it.
22+
*
23+
* @param Product $product
24+
* @param array $productData
25+
* @param array $useDefaults
26+
* @return array
27+
*/
28+
public function prepareProductAttributes(Product $product, array $productData, array $useDefaults)
29+
{
30+
foreach ($productData as $attribute => $value) {
31+
$considerUseDefaultsAttribute = !isset($useDefaults[$attribute]) || $useDefaults[$attribute] === "1";
32+
if ($value === '' && $considerUseDefaultsAttribute) {
33+
/** @var $product Product */
34+
if ((bool)$product->getData($attribute) === (bool)$value) {
35+
unset($productData[$attribute]);
36+
}
37+
}
38+
}
39+
return $productData;
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Initialization\Helper;
7+
8+
use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper\AttributeFilter;
9+
use Magento\Catalog\Model\Product;
10+
11+
class AttributeFilterTest extends \PHPUnit\Framework\TestCase
12+
{
13+
/**
14+
* @var AttributeFilter
15+
*/
16+
protected $model;
17+
18+
/**
19+
* @var \PHPUnit_Framework_MockObject_MockObject
20+
*/
21+
protected $objectManagerMock;
22+
23+
/**
24+
* @var Product|\PHPUnit_Framework_MockObject_MockObject
25+
*/
26+
protected $productMock;
27+
28+
protected function setUp()
29+
{
30+
$objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
31+
$this->model = $objectHelper->getObject(AttributeFilter::class);
32+
}
33+
34+
/**
35+
* @param array $requestProductData
36+
* @param array $useDefaults
37+
* @param array $expectedProductData
38+
* @param array $initialProductData
39+
* @dataProvider setupInputDataProvider
40+
*/
41+
public function testPrepareProductAttributes(
42+
$requestProductData,
43+
$useDefaults,
44+
$expectedProductData,
45+
$initialProductData
46+
) {
47+
$productMockMap = $this->getMockBuilder(Product::class)
48+
->disableOriginalConstructor()
49+
->setMethods(['getData'])
50+
->getMock();
51+
52+
if (!empty($initialProductData)) {
53+
$productMockMap->expects($this->any())->method('getData')->willReturnMap($initialProductData);
54+
}
55+
56+
$actualProductData = $this->model->prepareProductAttributes($productMockMap, $requestProductData, $useDefaults);
57+
$this->assertEquals($expectedProductData, $actualProductData);
58+
}
59+
60+
/**
61+
* @return array
62+
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
63+
*/
64+
public function setupInputDataProvider()
65+
{
66+
return [
67+
'create_new_product' => [
68+
'productData' => [
69+
'name' => 'testName',
70+
'sku' => 'testSku',
71+
'price' => '100',
72+
'description' => ''
73+
],
74+
'useDefaults' => [],
75+
'expectedProductData' => [
76+
'name' => 'testName',
77+
'sku' => 'testSku',
78+
'price' => '100'
79+
],
80+
'initialProductData' => []
81+
],
82+
'update_product_without_use_defaults' => [
83+
'productData' => [
84+
'name' => 'testName2',
85+
'sku' => 'testSku2',
86+
'price' => '101',
87+
'description' => '',
88+
'special_price' => null
89+
],
90+
'useDefaults' => [],
91+
'expectedProductData' => [
92+
'name' => 'testName2',
93+
'sku' => 'testSku2',
94+
'price' => '101',
95+
'special_price' => null
96+
],
97+
'initialProductData' => [
98+
['name', 'testName2'],
99+
['sku', 'testSku2'],
100+
['price', '101'],
101+
['special_price', null]
102+
]
103+
],
104+
'update_product_without_use_defaults_2' => [
105+
'productData' => [
106+
'name' => 'testName2',
107+
'sku' => 'testSku2',
108+
'price' => '101',
109+
'description' => 'updated description',
110+
'special_price' => null
111+
],
112+
'useDefaults' => [],
113+
'expectedProductData' => [
114+
'name' => 'testName2',
115+
'sku' => 'testSku2',
116+
'price' => '101',
117+
'description' => 'updated description',
118+
'special_price' => null
119+
],
120+
'initialProductData' => [
121+
['name', 'testName2'],
122+
['sku', 'testSku2'],
123+
['price', '101'],
124+
['special_price', null]
125+
]
126+
],
127+
'update_product_with_use_defaults' => [
128+
'productData' => [
129+
'name' => 'testName2',
130+
'sku' => 'testSku2',
131+
'price' => '101',
132+
'description' => '',
133+
'special_price' => null
134+
],
135+
'useDefaults' => [
136+
'description' => '0'
137+
],
138+
'expectedProductData' => [
139+
'name' => 'testName2',
140+
'sku' => 'testSku2',
141+
'price' => '101',
142+
'special_price' => null,
143+
'description' => ''
144+
],
145+
'initialProductData' => [
146+
['name', 'testName2'],
147+
['sku', 'testSku2'],
148+
['price', '101'],
149+
['special_price', null],
150+
['description', 'descr text']
151+
]
152+
],
153+
'update_product_with_use_defaults_2' => [
154+
'requestProductData' => [
155+
'name' => 'testName3',
156+
'sku' => 'testSku3',
157+
'price' => '103',
158+
'description' => 'descr modified',
159+
'special_price' => '100'
160+
],
161+
'useDefaults' => [
162+
'description' => '0'
163+
],
164+
'expectedProductData' => [
165+
'name' => 'testName3',
166+
'sku' => 'testSku3',
167+
'price' => '103',
168+
'special_price' => '100',
169+
'description' => 'descr modified'
170+
],
171+
'initialProductData' => [
172+
['name', null,'testName2'],
173+
['sku', null, 'testSku2'],
174+
['price', null, '101'],
175+
['description', null, 'descr text']
176+
]
177+
],
178+
'update_product_with_use_defaults_3' => [
179+
'requestProductData' => [
180+
'name' => 'testName3',
181+
'sku' => 'testSku3',
182+
'price' => '103',
183+
'special_price' => '100'
184+
],
185+
'useDefaults' => [
186+
'description' => '1'
187+
],
188+
'expectedProductData' => [
189+
'name' => 'testName3',
190+
'sku' => 'testSku3',
191+
'price' => '103',
192+
'special_price' => '100',
193+
],
194+
'initialProductData' => [
195+
['name', null,'testName2'],
196+
['sku', null, 'testSku2'],
197+
['price', null, '101'],
198+
['description', null, 'descr text']
199+
]
200+
],
201+
];
202+
}
203+
}

app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Magento\Catalog\Model\Product\LinkTypeProvider;
2121
use Magento\Catalog\Api\Data\ProductLinkTypeInterface;
2222
use Magento\Catalog\Model\ProductLink\Link as ProductLink;
23+
use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper\AttributeFilter;
2324

2425
/**
2526
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -89,6 +90,11 @@ class HelperTest extends \PHPUnit\Framework\TestCase
8990
*/
9091
protected $productLinksMock;
9192

93+
/**
94+
* @var AttributeFilter|\PHPUnit_Framework_MockObject_MockObject
95+
*/
96+
protected $attributeFilterMock;
97+
9298
protected function setUp()
9399
{
94100
$this->objectManager = new ObjectManager($this);
@@ -134,6 +140,10 @@ protected function setUp()
134140
$this->productLinksMock->expects($this->any())
135141
->method('initializeLinks')
136142
->willReturn($this->productMock);
143+
$this->attributeFilterMock = $this->getMockBuilder(AttributeFilter::class)
144+
->setMethods(['prepareProductAttributes'])
145+
->disableOriginalConstructor()
146+
->getMock();
137147

138148
$this->helper = $this->objectManager->getObject(
139149
Helper::class,
@@ -146,6 +156,7 @@ protected function setUp()
146156
'productLinkFactory' => $this->productLinkFactoryMock,
147157
'productRepository' => $this->productRepositoryMock,
148158
'linkTypeProvider' => $this->linkTypeProviderMock,
159+
'attributeFilter' => $this->attributeFilterMock
149160
]
150161
);
151162

@@ -269,6 +280,8 @@ public function testInitialize(
269280
->getMock();
270281
});
271282

283+
$this->attributeFilterMock->expects($this->any())->method('prepareProductAttributes')->willReturnArgument(1);
284+
272285
$this->assertEquals($this->productMock, $this->helper->initialize($this->productMock));
273286
$this->assertEquals($expWebsiteIds, $this->productMock->getDataByKey('website_ids'));
274287

0 commit comments

Comments
 (0)