Skip to content

Commit 3f9af07

Browse files
committed
Merge remote-tracking branch 'mainline/2.2-develop' into 2.2.5-merged
2 parents 9ad1a9a + 9f0ef00 commit 3f9af07

File tree

8 files changed

+246
-52
lines changed

8 files changed

+246
-52
lines changed

app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public function beforeSave($object)
9999
$object->setData($this->additionalData . $attributeName, $value);
100100
$object->setData($attributeName, $imageName);
101101
} elseif (!is_string($value)) {
102-
$object->setData($attributeName, '');
102+
$object->setData($attributeName, null);
103103
}
104104

105105
return parent::beforeSave($object);

app/code/Magento/Catalog/Model/Product/Attribute/Repository.php

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -122,39 +122,18 @@ public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attrib
122122
$this->processAttributeData($attribute);
123123
}
124124

125-
if (is_array($attribute->getFrontendLabels())) {
126-
$defaultFrontendLabel = $attribute->getDefaultFrontendLabel();
127-
$frontendLabel[0] = !empty($defaultFrontendLabel)
128-
? $defaultFrontendLabel
129-
: $existingModel->getDefaultFrontendLabel();
130-
foreach ($attribute->getFrontendLabels() as $item) {
131-
$frontendLabel[$item->getStoreId()] = $item->getLabel();
132-
}
133-
$attribute->setDefaultFrontendLabel($frontendLabel);
134-
}
125+
$this->updateDefaultFrontendLabel($attribute, $existingModel);
135126
} else {
136127
$attribute->setAttributeId(null);
137128

138129
if (!$attribute->getFrontendLabels() && !$attribute->getDefaultFrontendLabel()) {
139130
throw InputException::requiredField('frontend_label');
140131
}
141132

142-
$frontendLabels = [];
143-
if ($attribute->getDefaultFrontendLabel()) {
144-
$frontendLabels[0] = $attribute->getDefaultFrontendLabel();
145-
}
146-
if ($attribute->getFrontendLabels() && is_array($attribute->getFrontendLabels())) {
147-
foreach ($attribute->getFrontendLabels() as $label) {
148-
$frontendLabels[$label->getStoreId()] = $label->getLabel();
149-
}
150-
if (!isset($frontendLabels[0]) || !$frontendLabels[0]) {
151-
throw InputException::invalidFieldValue('frontend_label', null);
152-
}
133+
$frontendLabel = $this->updateDefaultFrontendLabel($attribute, null);
153134

154-
$attribute->setDefaultFrontendLabel($frontendLabels);
155-
}
156135
$attribute->setAttributeCode(
157-
$attribute->getAttributeCode() ?: $this->generateCode($frontendLabels[0])
136+
$attribute->getAttributeCode() ?: $this->generateCode($frontendLabel)
158137
);
159138
$this->validateCode($attribute->getAttributeCode());
160139
$this->validateFrontendInput($attribute->getFrontendInput());
@@ -289,4 +268,52 @@ private function processAttributeData(\Magento\Catalog\Api\Data\ProductAttribute
289268
$this->productHelper->getAttributeBackendModelByInputType($attribute->getFrontendInput())
290269
);
291270
}
271+
272+
/**
273+
* This method sets default frontend value using given default frontend value or frontend value from admin store
274+
* if default frontend value is not presented.
275+
* If both default frontend label and admin store frontend label are not given it throws exception
276+
* for attribute creation process or sets existing attribute value for attribute update action.
277+
*
278+
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
279+
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface|null $existingModel
280+
* @return string|null
281+
* @throws InputException
282+
*/
283+
private function updateDefaultFrontendLabel($attribute, $existingModel)
284+
{
285+
$frontendLabel = $attribute->getDefaultFrontendLabel();
286+
if (empty($frontendLabel)) {
287+
$frontendLabel = $this->extractAdminStoreFrontendLabel($attribute);
288+
if (empty($frontendLabel)) {
289+
if ($existingModel) {
290+
$frontendLabel = $existingModel->getDefaultFrontendLabel();
291+
} else {
292+
throw InputException::invalidFieldValue('frontend_label', null);
293+
}
294+
}
295+
$attribute->setDefaultFrontendLabel($frontendLabel);
296+
}
297+
return $frontendLabel;
298+
}
299+
300+
/**
301+
* This method extracts frontend label from FrontendLabel object for admin store.
302+
*
303+
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
304+
* @return string|null
305+
*/
306+
private function extractAdminStoreFrontendLabel($attribute)
307+
{
308+
$frontendLabel = [];
309+
$frontendLabels = $attribute->getFrontendLabels();
310+
if (isset($frontendLabels[0])
311+
&& $frontendLabels[0] instanceof \Magento\Eav\Api\Data\AttributeFrontendLabelInterface
312+
) {
313+
foreach ($attribute->getFrontendLabels() as $label) {
314+
$frontendLabel[$label->getStoreId()] = $label->getLabel();
315+
}
316+
}
317+
return $frontendLabel[0] ?? null;
318+
}
292319
}

app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public function testBeforeSaveValueDeletion($value)
8888

8989
$model->beforeSave($object);
9090

91-
$this->assertEquals('', $object->getTestAttribute());
91+
$this->assertEquals(null, $object->getTestAttribute());
9292
}
9393

9494
/**

app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/RepositoryTest.php

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1313
use Magento\Catalog\Model\Product\Attribute\Repository;
1414
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
15-
use Magento\Eav\Api\Data\AttributeFrontendLabelInterface;
1615

1716
/**
1817
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -87,7 +86,10 @@ protected function setUp()
8786
$this->eavConfigMock = $this->createMock(\Magento\Eav\Model\Config::class);
8887
$this->eavConfigMock->expects($this->any())->method('getEntityType')
8988
->willReturn(new \Magento\Framework\DataObject(['default_attribute_set_id' => 4]));
90-
$this->validatorFactoryMock = $this->createPartialMock(\Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\ValidatorFactory::class, ['create']);
89+
$this->validatorFactoryMock = $this->createPartialMock(
90+
\Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\ValidatorFactory::class,
91+
['create']
92+
);
9193
$this->searchCriteriaBuilderMock =
9294
$this->createMock(\Magento\Framework\Api\SearchCriteriaBuilder::class);
9395
$this->searchResultMock =
@@ -210,7 +212,10 @@ public function testSaveNoSuchEntityException()
210212
*/
211213
public function testSaveInputExceptionRequiredField()
212214
{
213-
$attributeMock = $this->createPartialMock(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, ['getFrontendLabels', 'getDefaultFrontendLabel', '__wakeup', 'getAttributeId', 'setAttributeId']);
215+
$attributeMock = $this->createPartialMock(
216+
\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class,
217+
['getFrontendLabels', 'getDefaultFrontendLabel', '__wakeup', 'getAttributeId', 'setAttributeId']
218+
);
214219
$attributeMock->expects($this->once())->method('getAttributeId')->willReturn(null);
215220
$attributeMock->expects($this->once())->method('setAttributeId')->with(null)->willReturnSelf();
216221
$attributeMock->expects($this->once())->method('getFrontendLabels')->willReturn(null);
@@ -225,12 +230,15 @@ public function testSaveInputExceptionRequiredField()
225230
*/
226231
public function testSaveInputExceptionInvalidFieldValue()
227232
{
228-
$attributeMock = $this->createPartialMock(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, ['getFrontendLabels', 'getDefaultFrontendLabel', 'getAttributeId', '__wakeup', 'setAttributeId']);
233+
$attributeMock = $this->createPartialMock(
234+
\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class,
235+
['getFrontendLabels', 'getDefaultFrontendLabel', 'getAttributeId', '__wakeup', 'setAttributeId']
236+
);
229237
$attributeMock->expects($this->once())->method('getAttributeId')->willReturn(null);
230238
$attributeMock->expects($this->once())->method('setAttributeId')->with(null)->willReturnSelf();
231-
$labelMock = $this->createMock(\Magento\Eav\Api\Data\AttributeFrontendLabelInterface::class);
232-
$attributeMock->expects($this->exactly(4))->method('getFrontendLabels')->willReturn([$labelMock]);
233-
$attributeMock->expects($this->exactly(2))->method('getDefaultFrontendLabel')->willReturn('test');
239+
$labelMock = $this->createMock(\Magento\Eav\Model\Entity\Attribute\FrontendLabel::class);
240+
$attributeMock->expects($this->any())->method('getFrontendLabels')->willReturn([$labelMock]);
241+
$attributeMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn(null);
234242
$labelMock->expects($this->once())->method('getStoreId')->willReturn(0);
235243
$labelMock->expects($this->once())->method('getLabel')->willReturn(null);
236244

@@ -253,7 +261,7 @@ public function testSaveDoesNotSaveAttributeOptionsIfOptionsAreAbsentInPayload()
253261
->method('get')
254262
->with(ProductAttributeInterface::ENTITY_TYPE_CODE, $attributeCode)
255263
->willReturn($existingModelMock);
256-
264+
$existingModelMock->expects($this->once())->method('getDefaultFrontendLabel')->willReturn('default_label');
257265
// Attribute code must not be changed after attribute creation
258266
$attributeMock->expects($this->once())->method('setAttributeCode')->with($attributeCode);
259267
$this->attributeResourceMock->expects($this->once())->method('save')->with($attributeMock);
@@ -264,7 +272,7 @@ public function testSaveDoesNotSaveAttributeOptionsIfOptionsAreAbsentInPayload()
264272

265273
public function testSaveSavesDefaultFrontendLabelIfItIsPresentInPayload()
266274
{
267-
$labelMock = $this->createMock(AttributeFrontendLabelInterface::class);
275+
$labelMock = $this->createMock(\Magento\Eav\Api\Data\AttributeFrontendLabelInterface::class);
268276
$labelMock->expects($this->any())->method('getStoreId')->willReturn(1);
269277
$labelMock->expects($this->any())->method('getLabel')->willReturn('Store Scope Label');
270278

@@ -273,11 +281,12 @@ public function testSaveSavesDefaultFrontendLabelIfItIsPresentInPayload()
273281
$attributeMock = $this->createMock(Attribute::class);
274282
$attributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
275283
$attributeMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId);
276-
$attributeMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn('Default Label');
284+
$attributeMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn(null);
277285
$attributeMock->expects($this->any())->method('getFrontendLabels')->willReturn([$labelMock]);
278286
$attributeMock->expects($this->any())->method('getOptions')->willReturn([]);
279287

280288
$existingModelMock = $this->createMock(Attribute::class);
289+
$existingModelMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn('Default Label');
281290
$existingModelMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId);
282291
$existingModelMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
283292

@@ -288,12 +297,7 @@ public function testSaveSavesDefaultFrontendLabelIfItIsPresentInPayload()
288297

289298
$attributeMock->expects($this->once())
290299
->method('setDefaultFrontendLabel')
291-
->with(
292-
[
293-
0 => 'Default Label',
294-
1 => 'Store Scope Label'
295-
]
296-
);
300+
->with('Default Label');
297301
$this->attributeResourceMock->expects($this->once())->method('save')->with($attributeMock);
298302

299303
$this->model->save($attributeMock);

app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
119119
*/
120120
protected $dataObjectHelper;
121121

122+
/**
123+
* @var FrontendLabelFactory
124+
*/
125+
private $frontendLabelFactory;
126+
122127
/**
123128
* Serializer Instance.
124129
*
@@ -157,6 +162,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
157162
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
158163
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
159164
* @param array $data
165+
* @param FrontendLabelFactory|null $frontendLabelFactory
160166
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
161167
* @codeCoverageIgnore
162168
*/
@@ -175,7 +181,8 @@ public function __construct(
175181
\Magento\Framework\Api\DataObjectHelper $dataObjectHelper,
176182
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
177183
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
178-
array $data = []
184+
array $data = [],
185+
FrontendLabelFactory $frontendLabelFactory = null
179186
) {
180187
parent::__construct(
181188
$context,
@@ -194,6 +201,8 @@ public function __construct(
194201
$this->optionDataFactory = $optionDataFactory;
195202
$this->dataObjectProcessor = $dataObjectProcessor;
196203
$this->dataObjectHelper = $dataObjectHelper;
204+
$this->frontendLabelFactory = $frontendLabelFactory
205+
?: \Magento\Framework\App\ObjectManager::getInstance()->get(FrontendLabelFactory::class);
197206
}
198207

199208
/**
@@ -1220,6 +1229,19 @@ public function setDefaultFrontendLabel($defaultFrontendLabel)
12201229
*/
12211230
public function getFrontendLabels()
12221231
{
1232+
if ($this->getData(self::FRONTEND_LABELS) == null) {
1233+
$attributeId = $this->getAttributeId();
1234+
$storeLabels = $this->_getResource()->getStoreLabelsByAttributeId($attributeId);
1235+
1236+
$resultFrontedLabels = [];
1237+
foreach ($storeLabels as $i => $label) {
1238+
$frontendLabel = $this->frontendLabelFactory->create();
1239+
$frontendLabel->setStoreId($i);
1240+
$frontendLabel->setLabel($label);
1241+
$resultFrontedLabels[] = $frontendLabel;
1242+
}
1243+
$this->setData(self::FRONTEND_LABELS, $resultFrontedLabels);
1244+
}
12231245
return $this->_getData(self::FRONTEND_LABELS);
12241246
}
12251247

app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute.php

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ protected function _beforeSave(AbstractModel $object)
170170
{
171171
$frontendLabel = $object->getFrontendLabel();
172172
if (is_array($frontendLabel)) {
173-
if (!isset($frontendLabel[0]) || $frontendLabel[0] === null || $frontendLabel[0] == '') {
174-
throw new \Magento\Framework\Exception\LocalizedException(__('The storefront label is not defined.'));
175-
}
173+
$this->checkDefaultFrontendLabelExists($frontendLabel, $frontendLabel);
176174
$object->setFrontendLabel($frontendLabel[0])->setStoreLabels($frontendLabel);
175+
} else {
176+
$this->setStoreLabels($object, $frontendLabel);
177177
}
178178

179179
/**
@@ -739,4 +739,43 @@ public function __wakeup()
739739
$this->_storeManager = \Magento\Framework\App\ObjectManager::getInstance()
740740
->get(\Magento\Store\Model\StoreManagerInterface::class);
741741
}
742+
743+
/**
744+
* This method extracts frontend labels into array and sets array values as storeLabels into an object.
745+
*
746+
* @param AbstractModel $object
747+
* @param string|null $frontendLabel
748+
* @return void
749+
* @throws \Magento\Framework\Exception\LocalizedException
750+
*/
751+
private function setStoreLabels(AbstractModel $object, $frontendLabel)
752+
{
753+
$resultLabel = [];
754+
$frontendLabels = $object->getFrontendLabels();
755+
if (isset($frontendLabels[0])
756+
&& $frontendLabels[0] instanceof \Magento\Eav\Model\Entity\Attribute\FrontendLabel
757+
) {
758+
foreach ($frontendLabels as $label) {
759+
$resultLabel[$label->getStoreId()] = $label->getLabel();
760+
}
761+
$this->checkDefaultFrontendLabelExists($frontendLabel, $resultLabel);
762+
$object->setStoreLabels($resultLabel);
763+
}
764+
}
765+
766+
/**
767+
* This method checks whether value for default frontend label exists in attribute data.
768+
*
769+
* @param array|string|null $frontendLabel
770+
* @param array $resultLabels
771+
* @return void
772+
* @throws \Magento\Framework\Exception\LocalizedException
773+
*/
774+
private function checkDefaultFrontendLabelExists($frontendLabel, $resultLabels)
775+
{
776+
$isAdminStoreLabel = (isset($resultLabels[0]) && !empty($resultLabels[0]));
777+
if (empty($frontendLabel) && !$isAdminStoreLabel) {
778+
throw new \Magento\Framework\Exception\LocalizedException(__('The storefront label is not defined.'));
779+
}
780+
}
742781
}

app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,39 @@ public function getSortWeightDataProvider()
112112
]
113113
];
114114
}
115+
116+
public function testGetFrontendLabels()
117+
{
118+
$attributeId = 1;
119+
$storeLabels = ['test_attribute_store1'];
120+
$frontendLabelFactory = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\FrontendLabelFactory::class)
121+
->setMethods(['create'])
122+
->getMock();
123+
$resource = $this->getMockBuilder(\Magento\Eav\Model\ResourceModel\Entity\Attribute::class)
124+
->setMethods(['getStoreLabelsByAttributeId'])
125+
->disableOriginalConstructor()
126+
->getMock();
127+
$arguments = [
128+
'_resource' => $resource,
129+
'frontendLabelFactory' => $frontendLabelFactory,
130+
];
131+
$objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
132+
$this->_model = $objectManager->getObject(\Magento\Eav\Model\Entity\Attribute::class, $arguments);
133+
$this->_model->setAttributeId($attributeId);
134+
135+
$resource->expects($this->once())
136+
->method('getStoreLabelsByAttributeId')
137+
->with($attributeId)
138+
->willReturn($storeLabels);
139+
$frontendLabel = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\FrontendLabel::class)
140+
->setMethods(['setStoreId', 'setLabel'])
141+
->disableOriginalConstructor()
142+
->getMock();
143+
$frontendLabelFactory->expects($this->once())
144+
->method('create')
145+
->willReturn($frontendLabel);
146+
$expectedFrontendLabel[] = $frontendLabel;
147+
148+
$this->assertEquals($expectedFrontendLabel, $this->_model->getFrontendLabels());
149+
}
115150
}

0 commit comments

Comments
 (0)