Skip to content

Commit 014408c

Browse files
mohaelmrabet-sqlisumesh-GL
authored andcommitted
Fix: preserve existing store labels when updating attribute option via API (issue #40093)
1 parent 6dd3fa9 commit 014408c

File tree

3 files changed

+58
-9
lines changed

3 files changed

+58
-9
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Magento\Eav\Api\Data\AttributeOptionInterface;
1414
use Magento\Eav\Model\AttributeRepository;
1515
use Magento\Eav\Model\ResourceModel\Entity\Attribute;
16+
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option;
1617
use Magento\Framework\Exception\InputException;
1718
use Magento\Framework\Exception\NoSuchEntityException;
1819
use Magento\Framework\Exception\StateException;
@@ -32,17 +33,25 @@ class OptionManagement implements AttributeOptionManagementInterface, AttributeO
3233
*/
3334
protected $resourceModel;
3435

36+
/**
37+
* @var Attribute\Option
38+
*/
39+
protected Attribute\Option $optionResource;
40+
3541
/**
3642
* @param AttributeRepository $attributeRepository
3743
* @param Attribute $resourceModel
44+
* @param Option $optionResource
3845
* @codeCoverageIgnore
3946
*/
4047
public function __construct(
4148
AttributeRepository $attributeRepository,
42-
Attribute $resourceModel
49+
Attribute $resourceModel,
50+
Attribute\Option $optionResource
4351
) {
4452
$this->attributeRepository = $attributeRepository;
4553
$this->resourceModel = $resourceModel;
54+
$this->optionResource = $optionResource;
4655
}
4756

4857
/**
@@ -140,6 +149,11 @@ private function saveOption(
140149
$options['value'][$optionId][0] = $optionLabel;
141150
$options['order'][$optionId] = $option->getSortOrder();
142151
$options['is_default'][$optionId] = $option->getIsDefault();
152+
153+
$existingLabels = $this->optionResource->getStoreLabelsByOptionId((int)$optionId);
154+
foreach ($existingLabels as $storeId => $labelText) {
155+
$options['value'][$optionId][$storeId] = $labelText;
156+
}
143157
if (is_array($option->getStoreLabels())) {
144158
foreach ($option->getStoreLabels() as $label) {
145159
$options['value'][$optionId][$label->getStoreId()] = $label->getLabel();
@@ -148,7 +162,6 @@ private function saveOption(
148162
if ($option->getIsDefault()) {
149163
$attribute->setDefault([$optionId]);
150164
}
151-
152165
$attribute->setOption($options);
153166
try {
154167
$this->resourceModel->save($attribute);

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,22 @@ public function getFlatUpdateSelect(
161161

162162
return $select;
163163
}
164+
165+
/**
166+
* Get all store labels for a given option ID
167+
*
168+
* @param int $optionId
169+
* @return array<int, string> [store_id => label]
170+
*/
171+
public function getStoreLabelsByOptionId(int $optionId): array
172+
{
173+
$connection = $this->getConnection();
174+
$table = $this->getTable('eav_attribute_option_value');
175+
176+
$select = $connection->select()
177+
->from($table, ['store_id', 'value'])
178+
->where('option_id = ?', $optionId);
179+
180+
return $connection->fetchPairs($select);
181+
}
164182
}

app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,23 @@ class OptionManagementTest extends TestCase
4444
*/
4545
protected $resourceModelMock;
4646

47+
/**
48+
* @var MockObject|Attribute\Option
49+
*/
50+
protected $optionResourceMock;
51+
4752
/**
4853
* @inheritdoc
4954
*/
5055
protected function setUp(): void
5156
{
5257
$this->attributeRepositoryMock = $this->createMock(AttributeRepository::class);
53-
$this->resourceModelMock =
54-
$this->createMock(Attribute::class);
58+
$this->resourceModelMock = $this->createMock(Attribute::class);
59+
$this->optionResourceMock = $this->createMock(Attribute\Option::class);
5560
$this->model = new OptionManagement(
5661
$this->attributeRepositoryMock,
57-
$this->resourceModelMock
62+
$this->resourceModelMock,
63+
$this->optionResourceMock
5864
);
5965
}
6066

@@ -255,6 +261,7 @@ public function testUpdate(string $label): void
255261
$optionId => [
256262
0 => $label,
257263
$storeId => $storeLabel,
264+
5 => 'otherLabelLabel'
258265
],
259266
],
260267
'order' => [
@@ -265,8 +272,17 @@ public function testUpdate(string $label): void
265272
]
266273
];
267274

275+
$this->optionResourceMock->expects($this->once())
276+
->method('getStoreLabelsByOptionId')
277+
->with($optionId)
278+
->willReturn([
279+
4 => 'oldLabelLabel',
280+
5 => 'otherLabelLabel'
281+
]);
282+
268283
$optionMock = $this->getAttributeOption();
269-
$labelMock = $this->getAttributeOptionLabel();
284+
$labelMock1 = $this->getAttributeOptionLabel();
285+
$labelMock2 = $this->getAttributeOptionLabel();
270286
/** @var SourceInterface|MockObject $sourceMock */
271287
$sourceMock = $this->createMock(EavAttributeSource::class);
272288

@@ -297,9 +313,11 @@ public function testUpdate(string $label): void
297313
$optionMock->method('getLabel')->willReturn($label);
298314
$optionMock->method('getSortOrder')->willReturn($sortOder);
299315
$optionMock->method('getIsDefault')->willReturn(true);
300-
$optionMock->method('getStoreLabels')->willReturn([$labelMock]);
301-
$labelMock->method('getStoreId')->willReturn($storeId);
302-
$labelMock->method('getLabel')->willReturn($storeLabel);
316+
$optionMock->method('getStoreLabels')->willReturn([$labelMock1, $labelMock2]);
317+
$labelMock1->method('getStoreId')->willReturn($storeId);
318+
$labelMock1->method('getLabel')->willReturn($storeLabel);
319+
$labelMock2->method('getStoreId')->willReturn(5);
320+
$labelMock2->method('getLabel')->willReturn('otherLabelLabel');
303321
$this->resourceModelMock->expects($this->once())->method('save')->with($attributeMock);
304322

305323
$this->assertEquals(

0 commit comments

Comments
 (0)