Skip to content

Commit 06311d1

Browse files
committed
ACP2E-3410: Configurable product edit form load causes timeout and memory exhaustion
1 parent 85a31d5 commit 06311d1

File tree

2 files changed

+116
-16
lines changed
  • app/code/Magento/ConfigurableProduct

2 files changed

+116
-16
lines changed

app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Matrix.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,16 +401,11 @@ private function buildAttributeDetails(AbstractAttribute $attribute): array
401401
*/
402402
private function buildChildProductOption(array $attributeDetails): array
403403
{
404-
$label = $this->extractAttributeValueLabel(
405-
$attributeDetails['attribute'],
406-
$attributeDetails['value_id']
407-
);
408-
409404
return [
410405
'attribute_code' => $attributeDetails['attribute']->getAttributeCode(),
411406
'attribute_label' => $attributeDetails['attribute']->getStoreLabel(0),
412407
'id' => $attributeDetails['value_id'],
413-
'label' => $label,
408+
'label' => $attributeDetails['label'],
414409
'value' => $attributeDetails['value_id'],
415410
'__disableTmpl' => true,
416411
];

app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProducts.php

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Magento\Framework\Json\Helper\Data as JsonHelper;
2020
use Magento\Framework\Locale\CurrencyInterface;
2121
use Magento\Framework\UrlInterface;
22+
use Magento\ConfigurableProduct\Model\Product\Type\VariationMatrix;
2223

2324
/**
2425
* Associated products helper
@@ -62,6 +63,11 @@ class AssociatedProducts
6263
*/
6364
protected $productIds = [];
6465

66+
/**
67+
* @var VariationMatrix
68+
*/
69+
protected $variationMatrix;
70+
6571
/**
6672
* @var UrlInterface
6773
*/
@@ -93,6 +99,7 @@ class AssociatedProducts
9399
* @param ConfigurableType $configurableType
94100
* @param ProductRepositoryInterface $productRepository
95101
* @param StockRegistryInterface $stockRegistry
102+
* @param VariationMatrix $variationMatrix
96103
* @param CurrencyInterface $localeCurrency
97104
* @param JsonHelper $jsonHelper
98105
* @param ImageHelper $imageHelper
@@ -105,6 +112,7 @@ public function __construct(
105112
ConfigurableType $configurableType,
106113
ProductRepositoryInterface $productRepository,
107114
StockRegistryInterface $stockRegistry,
115+
VariationMatrix $variationMatrix,
108116
CurrencyInterface $localeCurrency,
109117
JsonHelper $jsonHelper,
110118
ImageHelper $imageHelper,
@@ -115,6 +123,7 @@ public function __construct(
115123
$this->configurableType = $configurableType;
116124
$this->productRepository = $productRepository;
117125
$this->stockRegistry = $stockRegistry;
126+
$this->variationMatrix = $variationMatrix;
118127
$this->localeCurrency = $localeCurrency;
119128
$this->jsonHelper = $jsonHelper;
120129
$this->imageHelper = $imageHelper;
@@ -219,20 +228,104 @@ public function getConfigurableAttributesData()
219228
return $result;
220229
}
221230

231+
protected function prepareVariations2(): array
232+
{
233+
$variations = $this->getVariations();
234+
$productMatrix = [];
235+
$attributes = [];
236+
$productIds = [];
237+
if ($variations) {
238+
$usedProductAttributes = $this->getUsedAttributes();
239+
$productByUsedAttributes = $this->getAssociatedProducts();
240+
$currency = $this->localeCurrency->getCurrency($this->locator->getBaseCurrencyCode());
241+
$configurableAttributes = $this->getAttributes();
242+
foreach ($variations as $variation) {
243+
$attributeValues = [];
244+
foreach ($usedProductAttributes as $attribute) {
245+
$attributeValues[$attribute->getAttributeCode()] = $variation[$attribute->getId()]['value'];
246+
}
247+
$key = implode('-', $attributeValues);
248+
if (isset($productByUsedAttributes[$key])) {
249+
$product = $productByUsedAttributes[$key];
250+
$price = $product->getPrice();
251+
$variationOptions = [];
252+
foreach ($usedProductAttributes as $attribute) {
253+
if (!isset($attributes[$attribute->getAttributeId()])) {
254+
$attributes[$attribute->getAttributeId()] = [
255+
'code' => $attribute->getAttributeCode(),
256+
'label' => $attribute->getStoreLabel(),
257+
'id' => $attribute->getAttributeId(),
258+
'position' => $configurableAttributes[$attribute->getAttributeId()]['position'],
259+
'chosen' => [],
260+
];
261+
$options = $attribute->usesSource() ? $attribute->getSource()->getAllOptions() : [];
262+
foreach ($options as $option) {
263+
if (!empty($option['value'])) {
264+
$attributes[$attribute->getAttributeId()]['options'][$option['value']] = [
265+
'attribute_code' => $attribute->getAttributeCode(),
266+
'attribute_label' => $attribute->getStoreLabel(0),
267+
'id' => $option['value'],
268+
'label' => $option['label'],
269+
'value' => $option['value'],
270+
];
271+
}
272+
}
273+
}
274+
$optionId = $variation[$attribute->getId()]['value'];
275+
$variationOption = [
276+
'attribute_code' => $attribute->getAttributeCode(),
277+
'attribute_label' => $attribute->getStoreLabel(0),
278+
'id' => $optionId,
279+
'label' => $variation[$attribute->getId()]['label'],
280+
'value' => $optionId,
281+
];
282+
$variationOptions[] = $variationOption;
283+
$attributes[$attribute->getAttributeId()]['chosen'][$optionId] = $variationOption;
284+
}
285+
286+
$productMatrix[] = [
287+
'id' => $product->getId(),
288+
'product_link' => '<a href="' . $this->urlBuilder->getUrl(
289+
'catalog/product/edit',
290+
['id' => $product->getId()]
291+
) . '" target="_blank">' . $this->escaper->escapeHtml($product->getName()) . '</a>',
292+
'sku' => $product->getSku(),
293+
'name' => $product->getName(),
294+
'qty' => $this->getProductStockQty($product),
295+
'price' => $price,
296+
'price_string' => $currency->toCurrency(sprintf("%f", $price)),
297+
'price_currency' => $this->locator->getStore()->getBaseCurrency()->getCurrencySymbol(),
298+
'configurable_attribute' => $this->getJsonConfigurableAttributes($variationOptions),
299+
'weight' => $product->getWeight(),
300+
'status' => $product->getStatus(),
301+
'variationKey' => $this->getVariationKey($variationOptions),
302+
'canEdit' => 0,
303+
'newProduct' => 0,
304+
'attributes' => $this->getTextAttributes($variationOptions),
305+
'thumbnail_image' => $this->imageHelper->init($product, 'product_thumbnail_image')->getUrl(),
306+
];
307+
$productIds[] = $product->getId();
308+
}
309+
}
310+
}
311+
312+
return $productMatrix;
313+
//$this->productMatrix = $productMatrix;
314+
//$this->productIds = $productIds;
315+
}
316+
222317
/**
223318
* Prepare variations
224319
*
225320
* @return void
226321
* @throws CurrencyException
227-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
228-
* phpcs:disable Generic.Metrics.NestingLevel.TooHigh
229322
*/
230-
protected function prepareVariations()
323+
protected function prepareVariations(): void
231324
{
232325
$productMatrix = $attributes = [];
233326
$variants = $this->getVariantAttributeComposition();
234327
$productIds = [];
235-
foreach ($this->getAssociatedProducts() as $product) {
328+
foreach (array_reverse($this->getAssociatedProducts()) as $product) {
236329
$childProductOptions = [];
237330
$productIds[] = $product->getId();
238331
foreach ($variants[$product->getId()] as $attributeComposition) {
@@ -250,12 +343,13 @@ protected function prepareVariations()
250343
'label' => $attributeComposition['label'],
251344
'value' => $attributeComposition['value_id']
252345
];
253-
$attributes[$attribute->getAttributeId()]['chosen'][] = $variationOption;
346+
$attributes[$attribute->getAttributeId()]['chosen'][$attributeComposition['value_id']] =
347+
$variationOption;
254348
}
255349
$productMatrix[] = $this->buildChildProductDetails($product, $childProductOptions);
256350
}
257351

258-
$this->productMatrix = $productMatrix;
352+
$this->productMatrix = $this->prepareVariations2();
259353
$this->productIds = $productIds;
260354
$this->productAttributes = array_values($attributes);
261355
}
@@ -408,9 +502,10 @@ private function buildAttributeDetails(AbstractAttribute $attribute): array
408502
'chosen' => []
409503
];
410504

411-
foreach ($attribute->getOptions() as $option) {
505+
$options = $attribute->usesSource() ? $attribute->getSource()->getAllOptions() : [];
506+
foreach ($options as $option) {
412507
if (!empty($option['value'])) {
413-
$details['options'][] = [
508+
$details['options'][$option['value']] = [
414509
'attribute_code' => $attribute->getAttributeCode(),
415510
'attribute_label' => $attribute->getStoreLabel(0),
416511
'id' => $option['value'],
@@ -435,7 +530,7 @@ private function buildChildProductOption(array $attributeDetails): array
435530
'attribute_code' => $attributeDetails['attribute']->getAttributeCode(),
436531
'attribute_label' => $attributeDetails['attribute']->getStoreLabel(0),
437532
'id' => $attributeDetails['value_id'],
438-
'label' => $attributeDetails['value_id'],
533+
'label' => $attributeDetails['label'],
439534
'value' => $attributeDetails['value_id']
440535
];
441536
}
@@ -486,7 +581,7 @@ private function buildChildProductDetails(Product $product, array $childProductO
486581
'variationKey' => $this->getVariationKey($childProductOptions),
487582
'canEdit' => 0,
488583
'newProduct' => 0,
489-
'attributes' => $this->getTextAttributes($childProductOptions),
584+
'attributes' => $this->getTextAttributes($childProductOptions), //here be the problem
490585
'thumbnail_image' => $this->imageHelper->init($product, 'product_thumbnail_image')->getUrl(),
491586
];
492587
}
@@ -516,4 +611,14 @@ private function getVariantAttributeComposition(): array
516611

517612
return $variants;
518613
}
614+
615+
/**
616+
* Retrieve all possible attribute values combinations
617+
*
618+
* @return array
619+
*/
620+
protected function getVariations()
621+
{
622+
return $this->variationMatrix->getVariations($this->getAttributes());
623+
}
519624
}

0 commit comments

Comments
 (0)