Skip to content

Commit 5d91fa4

Browse files
MAGETWO-64315: [API] catalogProductAttributeRepository does not return "frontend_labels" value
1 parent 9b01481 commit 5d91fa4

File tree

6 files changed

+231
-46
lines changed

6 files changed

+231
-46
lines changed

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

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -119,39 +119,18 @@ public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attrib
119119
$attribute->setIsUserDefined($existingModel->getIsUserDefined());
120120
$attribute->setFrontendInput($existingModel->getFrontendInput());
121121

122-
if (is_array($attribute->getFrontendLabels())) {
123-
$defaultFrontendLabel = $attribute->getDefaultFrontendLabel();
124-
$frontendLabel[0] = !empty($defaultFrontendLabel)
125-
? $defaultFrontendLabel
126-
: $existingModel->getDefaultFrontendLabel();
127-
foreach ($attribute->getFrontendLabels() as $item) {
128-
$frontendLabel[$item->getStoreId()] = $item->getLabel();
129-
}
130-
$attribute->setDefaultFrontendLabel($frontendLabel);
131-
}
122+
$this->updateDefaultFrontendLabel($attribute, $existingModel);
132123
} else {
133124
$attribute->setAttributeId(null);
134125

135126
if (!$attribute->getFrontendLabels() && !$attribute->getDefaultFrontendLabel()) {
136127
throw InputException::requiredField('frontend_label');
137128
}
138129

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

151-
$attribute->setDefaultFrontendLabel($frontendLabels);
152-
}
153132
$attribute->setAttributeCode(
154-
$attribute->getAttributeCode() ?: $this->generateCode($frontendLabels[0])
133+
$attribute->getAttributeCode() ?: $this->generateCode($frontendLabel)
155134
);
156135
$this->validateCode($attribute->getAttributeCode());
157136
$this->validateFrontendInput($attribute->getFrontendInput());
@@ -275,4 +254,52 @@ protected function validateFrontendInput($frontendInput)
275254
throw InputException::invalidFieldValue('frontend_input', $frontendInput);
276255
}
277256
}
257+
258+
/**
259+
* This method sets default frontend value using given default frontend value or frontend value from admin store
260+
* if default frontend value is not presented.
261+
* If both default frontend label and admin store frontend label are not given it throws exception
262+
* for attribute creation process or sets existing attribute value for attribute update action.
263+
*
264+
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
265+
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface|null $existingModel
266+
* @return string|null
267+
* @throws InputException
268+
*/
269+
private function updateDefaultFrontendLabel($attribute, $existingModel)
270+
{
271+
$frontendLabel = $attribute->getDefaultFrontendLabel();
272+
if (empty($frontendLabel)) {
273+
$frontendLabel = $this->extractAdminStoreFrontendLabel($attribute);
274+
if (empty($frontendLabel)) {
275+
if ($existingModel) {
276+
$frontendLabel = $existingModel->getDefaultFrontendLabel();
277+
} else {
278+
throw InputException::invalidFieldValue('frontend_label', null);
279+
}
280+
}
281+
$attribute->setDefaultFrontendLabel($frontendLabel);
282+
}
283+
return $frontendLabel;
284+
}
285+
286+
/**
287+
* This method extracts frontend label from FrontendLabel object for admin store.
288+
*
289+
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
290+
* @return string|null
291+
*/
292+
private function extractAdminStoreFrontendLabel($attribute)
293+
{
294+
$frontendLabel = [];
295+
$frontendLabels = $attribute->getFrontendLabels();
296+
if (isset($frontendLabels[0])
297+
&& $frontendLabels[0] instanceof \Magento\Eav\Api\Data\AttributeFrontendLabelInterface
298+
) {
299+
foreach ($attribute->getFrontendLabels() as $label) {
300+
$frontendLabel[$label->getStoreId()] = $label->getLabel();
301+
}
302+
}
303+
return $frontendLabel[0] ?? null;
304+
}
278305
}

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

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1111
use Magento\Catalog\Model\Product\Attribute\Repository;
1212
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
13-
use Magento\Eav\Api\Data\AttributeFrontendLabelInterface;
1413

1514
/**
1615
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -235,9 +234,9 @@ public function testSaveInputExceptionInvalidFieldValue()
235234
);
236235
$attributeMock->expects($this->once())->method('getAttributeId')->willReturn(null);
237236
$attributeMock->expects($this->once())->method('setAttributeId')->with(null)->willReturnSelf();
238-
$labelMock = $this->createMock(\Magento\Eav\Api\Data\AttributeFrontendLabelInterface::class);
239-
$attributeMock->expects($this->exactly(4))->method('getFrontendLabels')->willReturn([$labelMock]);
240-
$attributeMock->expects($this->exactly(2))->method('getDefaultFrontendLabel')->willReturn('test');
237+
$labelMock = $this->createMock(\Magento\Eav\Model\Entity\Attribute\FrontendLabel::class);
238+
$attributeMock->expects($this->any())->method('getFrontendLabels')->willReturn([$labelMock]);
239+
$attributeMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn(null);
241240
$labelMock->expects($this->once())->method('getStoreId')->willReturn(0);
242241
$labelMock->expects($this->once())->method('getLabel')->willReturn(null);
243242

@@ -260,7 +259,7 @@ public function testSaveDoesNotSaveAttributeOptionsIfOptionsAreAbsentInPayload()
260259
->method('get')
261260
->with(ProductAttributeInterface::ENTITY_TYPE_CODE, $attributeCode)
262261
->willReturn($existingModelMock);
263-
262+
$existingModelMock->expects($this->once())->method('getDefaultFrontendLabel')->willReturn('default_label');
264263
// Attribute code must not be changed after attribute creation
265264
$attributeMock->expects($this->once())->method('setAttributeCode')->with($attributeCode);
266265
$this->attributeResourceMock->expects($this->once())->method('save')->with($attributeMock);
@@ -271,7 +270,7 @@ public function testSaveDoesNotSaveAttributeOptionsIfOptionsAreAbsentInPayload()
271270

272271
public function testSaveSavesDefaultFrontendLabelIfItIsPresentInPayload()
273272
{
274-
$labelMock = $this->createMock(AttributeFrontendLabelInterface::class);
273+
$labelMock = $this->createMock(\Magento\Eav\Api\Data\AttributeFrontendLabelInterface::class);
275274
$labelMock->expects($this->any())->method('getStoreId')->willReturn(1);
276275
$labelMock->expects($this->any())->method('getLabel')->willReturn('Store Scope Label');
277276

@@ -280,11 +279,12 @@ public function testSaveSavesDefaultFrontendLabelIfItIsPresentInPayload()
280279
$attributeMock = $this->createMock(Attribute::class);
281280
$attributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
282281
$attributeMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId);
283-
$attributeMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn('Default Label');
282+
$attributeMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn(null);
284283
$attributeMock->expects($this->any())->method('getFrontendLabels')->willReturn([$labelMock]);
285284
$attributeMock->expects($this->any())->method('getOptions')->willReturn([]);
286285

287286
$existingModelMock = $this->createMock(Attribute::class);
287+
$existingModelMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn('Default Label');
288288
$existingModelMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId);
289289
$existingModelMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
290290

@@ -295,12 +295,7 @@ public function testSaveSavesDefaultFrontendLabelIfItIsPresentInPayload()
295295

296296
$attributeMock->expects($this->once())
297297
->method('setDefaultFrontendLabel')
298-
->with(
299-
[
300-
0 => 'Default Label',
301-
1 => 'Store Scope Label'
302-
]
303-
);
298+
->with('Default Label');
304299
$this->attributeResourceMock->expects($this->once())->method('save')->with($attributeMock);
305300

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

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

Lines changed: 22 additions & 0 deletions
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
*
@@ -162,6 +167,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
162167
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
163168
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
164169
* @param array $data
170+
* @param FrontendLabelFactory|null $frontendLabelFactory
165171
* @param \Magento\Eav\Api\Data\AttributeExtensionFactory|null $eavExtensionFactory
166172
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
167173
* @codeCoverageIgnore
@@ -182,6 +188,7 @@ public function __construct(
182188
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
183189
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
184190
array $data = [],
191+
FrontendLabelFactory $frontendLabelFactory = null,
185192
\Magento\Eav\Api\Data\AttributeExtensionFactory $eavExtensionFactory = null
186193
) {
187194
parent::__construct(
@@ -203,6 +210,8 @@ public function __construct(
203210
$this->dataObjectHelper = $dataObjectHelper;
204211
$this->eavExtensionFactory = $eavExtensionFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
205212
->get(\Magento\Eav\Api\Data\AttributeExtensionFactory::class);
213+
$this->frontendLabelFactory = $frontendLabelFactory
214+
?: \Magento\Framework\App\ObjectManager::getInstance()->get(FrontendLabelFactory::class);
206215
}
207216

208217
/**
@@ -1234,6 +1243,19 @@ public function setDefaultFrontendLabel($defaultFrontendLabel)
12341243
*/
12351244
public function getFrontendLabels()
12361245
{
1246+
if ($this->getData(self::FRONTEND_LABELS) == null) {
1247+
$attributeId = $this->getAttributeId();
1248+
$storeLabels = $this->_getResource()->getStoreLabelsByAttributeId($attributeId);
1249+
1250+
$resultFrontedLabels = [];
1251+
foreach ($storeLabels as $i => $label) {
1252+
$frontendLabel = $this->frontendLabelFactory->create();
1253+
$frontendLabel->setStoreId($i);
1254+
$frontendLabel->setLabel($label);
1255+
$resultFrontedLabels[] = $frontendLabel;
1256+
}
1257+
$this->setData(self::FRONTEND_LABELS, $resultFrontedLabels);
1258+
}
12371259
return $this->_getData(self::FRONTEND_LABELS);
12381260
}
12391261

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

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

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

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)