Skip to content

Commit c9a6164

Browse files
committed
PWA-1326: Implement the schema changes for Configurable Options Selection
- combining schema with variant attribute details
1 parent 07592df commit c9a6164

File tree

3 files changed

+118
-36
lines changed

3 files changed

+118
-36
lines changed

app/code/Magento/ConfigurableProductGraphQl/Model/Options/ConfigurableOptionsMetadata.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/**
1717
* Retrieve metadata for configurable option selection.
1818
*/
19-
class Metadata
19+
class ConfigurableOptionsMetadata
2020
{
2121
/**
2222
* @var Data

app/code/Magento/ConfigurableProductGraphQl/Model/Options/Metadata.php

Lines changed: 117 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,84 +3,171 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6-
76
declare(strict_types=1);
87

98
namespace Magento\ConfigurableProductGraphQl\Model\Options;
109

1110
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Catalog\Api\ProductRepositoryInterface;
1212
use Magento\ConfigurableProduct\Helper\Data;
13-
use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;
14-
use Magento\ConfigurableProductGraphQl\Model\Formatter\Option;
13+
use Magento\ConfigurableProductGraphQl\Model\Options\DataProvider\Variant;
14+
use Magento\Framework\Exception\NoSuchEntityException;
1515

1616
/**
1717
* Retrieve metadata for configurable option selection.
1818
*/
19-
class ConfigurableOptionsMetadata
19+
class Metadata
2020
{
2121
/**
2222
* @var Data
2323
*/
2424
private $configurableProductHelper;
2525

2626
/**
27-
* @var Option
27+
* @var SelectionUidFormatter
28+
*/
29+
private $selectionUidFormatter;
30+
31+
/**
32+
* @var ProductRepositoryInterface
2833
*/
29-
private $configurableOptionsFormatter;
34+
private $productRepository;
35+
36+
/**
37+
* @var Variant
38+
*/
39+
private $variant;
3040

3141
/**
3242
* @param Data $configurableProductHelper
33-
* @param Option $configurableOptionsFormatter
43+
* @param SelectionUidFormatter $selectionUidFormatter
44+
* @param ProductRepositoryInterface $productRepository
45+
* @param Variant $variant
3446
*/
3547
public function __construct(
3648
Data $configurableProductHelper,
37-
Option $configurableOptionsFormatter
49+
SelectionUidFormatter $selectionUidFormatter,
50+
ProductRepositoryInterface $productRepository,
51+
Variant $variant
3852
) {
3953
$this->configurableProductHelper = $configurableProductHelper;
40-
$this->configurableOptionsFormatter = $configurableOptionsFormatter;
54+
$this->selectionUidFormatter = $selectionUidFormatter;
55+
$this->productRepository = $productRepository;
56+
$this->variant = $variant;
4157
}
4258

4359
/**
44-
* Load available selections from configurable options and variant.
60+
* Load available selections from configurable options.
4561
*
4662
* @param ProductInterface $product
47-
* @param array $options
48-
* @param array $selectedOptions
63+
* @param array $selectedOptionsUid
4964
* @return array
65+
* @throws NoSuchEntityException
66+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
5067
*/
51-
public function getAvailableSelections(ProductInterface $product, array $options, array $selectedOptions): array
52-
{
53-
$attributes = $this->getAttributes($product);
54-
$availableSelections = [];
68+
public function getAvailableSelections(
69+
ProductInterface $product,
70+
array $selectedOptionsUid
71+
): array {
72+
$options = $this->configurableProductHelper->getOptions($product, $this->getAllowProducts($product));
73+
$selectedOptions = $this->selectionUidFormatter->extract($selectedOptionsUid);
74+
$attributeCodes = $this->getAttributeCodes($product);
75+
$availableSelections = $availableProducts = $variantData = [];
5576

56-
foreach ($options as $attributeId => $option) {
57-
if ($attributeId === 'index' || isset($selectedOptions[$attributeId])) {
58-
continue;
77+
if (isset($options['index']) && $options['index']) {
78+
foreach ($options['index'] as $productId => $productOptions) {
79+
if (!empty($selectedOptions) && !$this->hasProductRequiredOptions($selectedOptions, $productOptions)) {
80+
continue;
81+
}
82+
83+
$availableProducts[] = $productId;
84+
foreach ($productOptions as $attributeId => $optionIndex) {
85+
$uid = $this->selectionUidFormatter->encode($attributeId, (int)$optionIndex);
86+
87+
if (isset($availableSelections[$attributeId]['option_value_uids'])
88+
&& in_array($uid, $availableSelections[$attributeId]['option_value_uids'])
89+
) {
90+
continue;
91+
}
92+
$availableSelections[$attributeId]['option_value_uids'][] = $uid;
93+
$availableSelections[$attributeId]['attribute_code'] = $attributeCodes[$attributeId];
94+
}
95+
96+
if ($this->hasSelectionProduct($selectedOptions, $productOptions)) {
97+
$variantProduct = $this->productRepository->getById($productId);
98+
$variantData = $variantProduct->getData();
99+
$variantData['model'] = $variantProduct;
100+
}
59101
}
102+
}
103+
104+
return [
105+
'options_available_for_selection' => $availableSelections,
106+
'variant' => $variantData,
107+
'availableSelectionProducts' => array_unique($availableProducts),
108+
'product' => $product
109+
];
110+
}
111+
112+
/**
113+
* Get allowed products.
114+
*
115+
* @param ProductInterface $product
116+
* @return ProductInterface[]
117+
*/
118+
public function getAllowProducts(ProductInterface $product): array
119+
{
120+
return $this->variant->getSalableVariantsByParent($product) ?? [];
121+
}
60122

61-
$availableSelections[] = $this->configurableOptionsFormatter->format(
62-
$attributes[$attributeId],
63-
$options[$attributeId] ?? []
64-
);
123+
/**
124+
* Check if a product has the selected options.
125+
*
126+
* @param array $requiredOptions
127+
* @param array $productOptions
128+
* @return bool
129+
*/
130+
private function hasProductRequiredOptions($requiredOptions, $productOptions): bool
131+
{
132+
$result = true;
133+
foreach ($requiredOptions as $attributeId => $optionIndex) {
134+
if (!isset($productOptions[$attributeId]) || !$productOptions[$attributeId]
135+
|| $optionIndex != $productOptions[$attributeId]
136+
) {
137+
$result = false;
138+
break;
139+
}
65140
}
66141

67-
return $availableSelections;
142+
return $result;
143+
}
144+
145+
/**
146+
* Check if selected options match a product.
147+
*
148+
* @param array $requiredOptions
149+
* @param array $productOptions
150+
* @return bool
151+
*/
152+
private function hasSelectionProduct($requiredOptions, $productOptions): bool
153+
{
154+
return $this->hasProductRequiredOptions($productOptions, $requiredOptions);
68155
}
69156

70157
/**
71-
* Retrieve configurable attributes for the product
158+
* Retrieve attribute codes
72159
*
73160
* @param ProductInterface $product
74-
* @return Attribute[]
161+
* @return string[]
75162
*/
76-
private function getAttributes(ProductInterface $product): array
163+
private function getAttributeCodes(ProductInterface $product): array
77164
{
78165
$allowedAttributes = $this->configurableProductHelper->getAllowAttributes($product);
79-
$attributes = [];
166+
$attributeCodes = [];
80167
foreach ($allowedAttributes as $attribute) {
81-
$attributes[$attribute->getAttributeId()] = $attribute;
168+
$attributeCodes[$attribute->getAttributeId()] = $attribute->getProductAttribute()->getAttributeCode();
82169
}
83170

84-
return $attributes;
171+
return $attributeCodes;
85172
}
86173
}

dev/tests/api-functional/testsuite/Magento/GraphQl/ConfigurableProduct/ConfigurableOptionsSelectionTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,6 @@ public function testSelectedVariant(): void
135135
self::assertIsString($product['configurable_product_options_selection']['variant']['sku']);
136136
$urlKey = 'configurable-option-first-option-1-second-option-1';
137137
self::assertEquals($urlKey, $product['configurable_product_options_selection']['variant']['url_key']);
138-
self::assertMatchesRegularExpression(
139-
"/{$urlKey}/",
140-
$product['configurable_product_options_selection']['variant']['url_path']
141-
);
142138

143139
$this->assertMediaGallery($product);
144140
}
@@ -264,7 +260,6 @@ private function getQuery(
264260
uid
265261
sku
266262
url_key
267-
url_path
268263
}
269264
media_gallery {
270265
url

0 commit comments

Comments
 (0)