diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index eb312a751a97d..4183d3c20c3ca 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -85,6 +85,11 @@ class Data */ private $swatchesCache = []; + /** + * @var array + */ + private $attributeOptionsCache = []; + /** * @var Json */ @@ -438,7 +443,7 @@ public function getSwatchAttributesAsArray(ProductInterface $product) foreach ($swatchAttributes as $swatchAttribute) { $swatchAttribute->setStoreId($this->storeManager->getStore()->getId()); $attributeData = $swatchAttribute->getData(); - foreach ($swatchAttribute->getSource()->getAllOptions(false) as $option) { + foreach ($this->getAttributeOptions($swatchAttribute, (int)$attributeData['attribute_id']) as $option) { $attributeData['options'][$option['value']] = $option['label']; } $result[$attributeData['attribute_id']] = $attributeData; @@ -447,6 +452,24 @@ public function getSwatchAttributesAsArray(ProductInterface $product) return $result; } + /** + * Retrieve attribute options with per-instance memoization. + * + * @param Attribute $attribute + * @param int $attributeId + * @return array + */ + private function getAttributeOptions(Attribute $attribute, int $attributeId): array + { + $cacheKey = $attributeId . '_' . (int)$attribute->getStoreId(); + + if (!isset($this->attributeOptionsCache[$cacheKey])) { + $this->attributeOptionsCache[$cacheKey] = $attribute->getSource()->getAllOptions(false); + } + + return $this->attributeOptionsCache[$cacheKey]; + } + /** * Get swatch options by option id's according to fallback logic * diff --git a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php index af070fc7937b5..c2189828fd8c2 100644 --- a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php @@ -664,6 +664,62 @@ public function testGetSwatchAttributesAsArray($optionsArray, $attributeData, $e $this->assertEquals($result, $expected); } + /** + * @return void + */ + public function testGetSwatchAttributesAsArrayMemoizesAttributeOptionsPerStore(): void + { + $storeOneOptions = [ + ['value' => 45, 'label' => 'green'], + ['value' => 46, 'label' => 'yellow'] + ]; + $storeTwoOptions = [ + ['value' => 45, 'label' => 'grun'], + ['value' => 46, 'label' => 'gelb'] + ]; + $attributeData = ['attribute_id' => 52]; + $expectedStoreOne = [ + 52 => [ + 'attribute_id' => 52, + 'options' => [ + 45 => 'green', + 46 => 'yellow' + ] + ] + ]; + $expectedStoreTwo = [ + 52 => [ + 'attribute_id' => 52, + 'options' => [ + 45 => 'grun', + 46 => 'gelb' + ] + ] + ]; + + $this->swatchAttributesProvider + ->method('provide') + ->with($this->productMock) + ->willReturn([$this->attributeMock]); + + $storeMock = $this->createMock(Store::class); + $storeMock->method('getId')->willReturnOnConsecutiveCalls(1, 1, 2); + $this->storeManagerMock->method('getStore')->willReturn($storeMock); + + $this->attributeMock->method('getData')->with('')->willReturn($attributeData); + + $sourceMock = $this->createMock(AbstractSource::class); + $sourceMock->expects($this->exactly(2)) + ->method('getAllOptions') + ->with(false) + ->willReturnOnConsecutiveCalls($storeOneOptions, $storeTwoOptions); + $this->attributeMock->method('getSource')->willReturn($sourceMock); + + $this->assertEquals($expectedStoreOne, $this->swatchHelperObject->getSwatchAttributesAsArray($this->productMock)); + $this->assertEquals($expectedStoreOne, $this->swatchHelperObject->getSwatchAttributesAsArray($this->productMock)); + $this->assertEquals($expectedStoreTwo, $this->swatchHelperObject->getSwatchAttributesAsArray($this->productMock)); + } + /** * @return array */