Skip to content

Commit 2a28e71

Browse files
committed
Merge branch 'ACP2E-3410' of https://github.com/adobe-commerce-tier-4/magento2ce into PR-VK-2024-11-27-CE
2 parents c85a0c7 + fdab6cf commit 2a28e71

File tree

6 files changed

+787
-246
lines changed

6 files changed

+787
-246
lines changed

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

Lines changed: 140 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2013 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Variations\Config;
77

88
use Magento\Catalog\Api\ProductRepositoryInterface;
99
use Magento\Catalog\Model\Locator\LocatorInterface;
1010
use Magento\Catalog\Model\Product;
11+
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
1112
use Magento\Framework\Exception\NoSuchEntityException;
1213

1314
/**
@@ -88,7 +89,7 @@ public function __construct(
8889
LocatorInterface $locator,
8990
array $data = []
9091
) {
91-
parent::__construct($context, $data);
92+
parent::__construct($context, $data, $data['jsonHelper'] ?? null, $data['directoryHelper'] ?? null);
9293
$this->_configurableType = $configurableType;
9394
$this->stockRegistry = $stockRegistry;
9495
$this->variationMatrix = $variationMatrix;
@@ -242,6 +243,32 @@ protected function getAssociatedProducts()
242243
return $productByUsedAttributes;
243244
}
244245

246+
/**
247+
* Retrieves attributes that are used for configurable product variations
248+
*
249+
* @return array
250+
*/
251+
private function getVariantAttributeComposition(): array
252+
{
253+
$variants = [];
254+
foreach ($this->_getAssociatedProducts() as $product) {
255+
/* @var $attribute AbstractAttribute */
256+
foreach ($this->getUsedAttributes() as $attribute) {
257+
$variants[$product->getId()][$attribute->getAttributeCode()] =
258+
[
259+
'value_id' => $product->getData($attribute->getAttributeCode()),
260+
'label' => $this->extractAttributeValueLabel(
261+
$attribute,
262+
$product->getData($attribute->getAttributeCode())
263+
),
264+
'attribute' => $attribute
265+
];
266+
}
267+
}
268+
269+
return $variants;
270+
}
271+
245272
/**
246273
* Retrieve actual list of associated products (i.e. if product contains variations matrix form data
247274
* - previously saved in database relations are not considered)
@@ -251,7 +278,7 @@ protected function getAssociatedProducts()
251278
protected function _getAssociatedProducts()
252279
{
253280
$product = $this->getProduct();
254-
$ids = $this->getProduct()->getAssociatedProductIds();
281+
$ids = $product->getAssociatedProductIds();
255282
if ($ids === null) {
256283
// form data overrides any relations stored in database
257284
return $this->_configurableType->getUsedProducts($product);
@@ -332,6 +359,76 @@ public function getProductAttributes()
332359
return $this->productAttributes;
333360
}
334361

362+
/**
363+
* Prepare attribute details for child product configuration
364+
*
365+
* @param AbstractAttribute $attribute
366+
* @return array
367+
*/
368+
private function buildAttributeDetails(AbstractAttribute $attribute): array
369+
{
370+
$configurableAttributes = $this->getAttributes();
371+
$details = [
372+
'code' => $attribute->getAttributeCode(),
373+
'label' => $attribute->getStoreLabel(),
374+
'id' => $attribute->getAttributeId(),
375+
'position' => $configurableAttributes[$attribute->getAttributeId()]['position'],
376+
'chosen' => [],
377+
'__disableTmpl' => true
378+
];
379+
380+
foreach ($attribute->getOptions() as $option) {
381+
if ($option->getValue()) {
382+
$details['options'][] = [
383+
'attribute_code' => $attribute->getAttributeCode(),
384+
'attribute_label' => $attribute->getStoreLabel(0),
385+
'id' => $option->getValue(),
386+
'label' => $option->getLabel(),
387+
'value' => $option->getValue(),
388+
'__disableTmpl' => true,
389+
];
390+
}
391+
}
392+
393+
return $details;
394+
}
395+
396+
/**
397+
* Generate configurable product child option
398+
*
399+
* @param array $attributeDetails
400+
* @return array
401+
*/
402+
private function buildChildProductOption(array $attributeDetails): array
403+
{
404+
return [
405+
'attribute_code' => $attributeDetails['attribute']->getAttributeCode(),
406+
'attribute_label' => $attributeDetails['attribute']->getStoreLabel(0),
407+
'id' => $attributeDetails['value_id'],
408+
'label' => $attributeDetails['label'],
409+
'value' => $attributeDetails['value_id'],
410+
'__disableTmpl' => true,
411+
];
412+
}
413+
414+
/**
415+
* Get label for a specific value of an attribute.
416+
*
417+
* @param AbstractAttribute $attribute
418+
* @param mixed $valueId
419+
* @return string
420+
*/
421+
private function extractAttributeValueLabel(AbstractAttribute $attribute, mixed $valueId): string
422+
{
423+
foreach ($attribute->getOptions() as $attributeOption) {
424+
if ($attributeOption->getValue() == $valueId) {
425+
return $attributeOption->getLabel();
426+
}
427+
}
428+
429+
return '';
430+
}
431+
335432
/**
336433
* Prepare product variations.
337434
*
@@ -341,106 +438,57 @@ public function getProductAttributes()
341438
*/
342439
protected function prepareVariations()
343440
{
344-
$variations = $this->getVariations();
345-
$productMatrix = [];
346-
$attributes = [];
347-
if ($variations) {
348-
$usedProductAttributes = $this->getUsedAttributes();
349-
$productByUsedAttributes = $this->getAssociatedProducts();
350-
$configurableAttributes = $this->getAttributes();
351-
foreach ($variations as $variation) {
352-
$attributeValues = [];
353-
foreach ($usedProductAttributes as $attribute) {
354-
$attributeValues[$attribute->getAttributeCode()] = $variation[$attribute->getId()]['value'];
355-
}
356-
$key = implode('-', $attributeValues);
357-
if (isset($productByUsedAttributes[$key])) {
358-
$product = $productByUsedAttributes[$key];
359-
$price = $product->getPrice();
360-
$variationOptions = [];
361-
foreach ($usedProductAttributes as $attribute) {
362-
list($attributes, $variationOptions) = $this->prepareAttributes(
363-
$attributes,
364-
$attribute,
365-
$configurableAttributes,
366-
$variation,
367-
$variationOptions
368-
);
369-
}
370-
371-
$productMatrix[] = [
372-
'productId' => $product->getId(),
373-
'images' => [
374-
'preview' => $this->image->init($product, 'product_thumbnail_image')->getUrl()
375-
],
376-
'sku' => $product->getSku(),
377-
'name' => $product->getName(),
378-
'quantity' => $this->getProductStockQty($product),
379-
'price' => $price,
380-
'options' => $variationOptions,
381-
'weight' => $product->getWeight(),
382-
'status' => $product->getStatus(),
383-
'__disableTmpl' => true,
384-
];
441+
$productMatrix = $attributes = [];
442+
$variants = $this->getVariantAttributeComposition();
443+
foreach (array_reverse($this->getAssociatedProducts()) as $product) {
444+
$childProductOptions = [];
445+
foreach ($variants[$product->getId()] as $attributeComposition) {
446+
$childProductOptions[] = $this->buildChildProductOption($attributeComposition);
447+
448+
/** @var AbstractAttribute $attribute */
449+
$attribute = $attributeComposition['attribute'];
450+
if (!isset($attributes[$attribute->getAttributeId()])) {
451+
$attributes[$attribute->getAttributeId()] = $this->buildAttributeDetails($attribute);
385452
}
453+
$variationOption = [
454+
'attribute_code' => $attribute->getAttributeCode(),
455+
'attribute_label' => $attribute->getStoreLabel(0),
456+
'id' => $attributeComposition['value_id'],
457+
'label' => $attributeComposition['label'],
458+
'value' => $attributeComposition['value_id'],
459+
'__disableTmpl' => true,
460+
];
461+
$attributes[$attribute->getAttributeId()]['chosen'][] = $variationOption;
386462
}
463+
$productMatrix[] = $this->buildChildProductDetails($product, $childProductOptions);
387464
}
465+
388466
$this->productMatrix = $productMatrix;
389467
$this->productAttributes = array_values($attributes);
390468
}
391469

392470
/**
393-
* Prepare attributes.
471+
* Create child product details
394472
*
395-
* @param array $attributes
396-
* @param object $attribute
397-
* @param array $configurableAttributes
398-
* @param array $variation
399-
* @param array $variationOptions
473+
* @param Product $product
474+
* @param array $childProductOptions
400475
* @return array
401476
*/
402-
private function prepareAttributes(
403-
array $attributes,
404-
$attribute,
405-
array $configurableAttributes,
406-
array $variation,
407-
array $variationOptions
408-
): array {
409-
if (!isset($attributes[$attribute->getAttributeId()])) {
410-
$attributes[$attribute->getAttributeId()] = [
411-
'code' => $attribute->getAttributeCode(),
412-
'label' => $attribute->getStoreLabel(),
413-
'id' => $attribute->getAttributeId(),
414-
'position' => $configurableAttributes[$attribute->getAttributeId()]['position'],
415-
'chosen' => [],
416-
'__disableTmpl' => true
417-
];
418-
$options = $attribute->usesSource() ? $attribute->getSource()->getAllOptions() : [];
419-
foreach ($options as $option) {
420-
if (!empty($option['value'])) {
421-
$attributes[$attribute->getAttributeId()]['options'][] = [
422-
'attribute_code' => $attribute->getAttributeCode(),
423-
'attribute_label' => $attribute->getStoreLabel(0),
424-
'id' => $option['value'],
425-
'label' => $option['label'],
426-
'value' => $option['value'],
427-
'__disableTmpl' => true,
428-
];
429-
}
430-
}
431-
}
432-
$optionId = $variation[$attribute->getId()]['value'];
433-
$variationOption = [
434-
'attribute_code' => $attribute->getAttributeCode(),
435-
'attribute_label' => $attribute->getStoreLabel(0),
436-
'id' => $optionId,
437-
'label' => $variation[$attribute->getId()]['label'],
438-
'value' => $optionId,
477+
private function buildChildProductDetails(Product $product, array $childProductOptions): array
478+
{
479+
return [
480+
'productId' => $product->getId(),
481+
'images' => [
482+
'preview' => $this->image->init($product, 'product_thumbnail_image')->getUrl()
483+
],
484+
'sku' => $product->getSku(),
485+
'name' => $product->getName(),
486+
'quantity' => $this->getProductStockQty($product),
487+
'price' => $product->getPrice(),
488+
'options' => $childProductOptions,
489+
'weight' => $product->getWeight(),
490+
'status' => $product->getStatus(),
439491
'__disableTmpl' => true,
440492
];
441-
$variationOptions[] = $variationOption;
442-
$attributes[$attribute->getAttributeId()]['chosen'][] = $variationOption;
443-
444-
return [$attributes, $variationOptions];
445493
}
446494
}

0 commit comments

Comments
 (0)