Skip to content

Commit beaad51

Browse files
author
Serhii Balko
committed
Merge remote-tracking branch 'origin/MC-41885' into 2.4-develop-pr58
2 parents 3320c6d + 001fde2 commit beaad51

File tree

5 files changed

+123
-78
lines changed

5 files changed

+123
-78
lines changed

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation;
99

1010
use Magento\Framework\App\ResourceConnection;
11+
use Magento\Framework\DB\Select;
1112
use Magento\Store\Model\Store;
1213

1314
/**
@@ -95,6 +96,8 @@ public function getOptions(array $optionIds, ?int $storeId, array $attributeCode
9596
)->where(
9697
'a.attribute_id = options.attribute_id AND option_value.store_id = ?',
9798
Store::DEFAULT_STORE_ID
99+
)->order(
100+
'options.sort_order ' . Select::SQL_ASC
98101
);
99102

100103
$select->where('option_value.option_id IN (?)', $optionIds);
@@ -112,11 +115,11 @@ public function getOptions(array $optionIds, ?int $storeId, array $attributeCode
112115
/**
113116
* Format result
114117
*
115-
* @param \Magento\Framework\DB\Select $select
118+
* @param Select $select
116119
* @return array
117120
* @throws \Zend_Db_Statement_Exception
118121
*/
119-
private function formatResult(\Magento\Framework\DB\Select $select): array
122+
private function formatResult(Select $select): array
120123
{
121124
$statement = $this->resourceConnection->getConnection()->query($select);
122125

@@ -131,7 +134,9 @@ private function formatResult(\Magento\Framework\DB\Select $select): array
131134
'options' => [],
132135
];
133136
}
134-
$result[$option['attribute_code']]['options'][$option['option_id']] = $option['option_label'];
137+
if (!empty($option['option_id'])) {
138+
$result[$option['attribute_code']]['options'][$option['option_id']] = $option['option_label'];
139+
}
135140
}
136141

137142
return $result;

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ public function build(AggregationInterface $aggregation, ?int $storeId): array
8686
$attribute['attribute_code'] ?? $bucketName
8787
);
8888

89-
foreach ($bucket->getValues() as $value) {
90-
$metrics = $value->getMetrics();
89+
$options = $this->getSortedOptions($bucket,$attribute['options'] ?: []);
90+
foreach ($options as $option) {
9191
$result[$bucketName]['options'][] = $this->layerFormatter->buildItem(
92-
$attribute['options'][$metrics['value']] ?? $metrics['value'],
93-
$metrics['value'],
94-
$metrics['count']
92+
$option['label'],
93+
$option['value'],
94+
$option['count']
9595
);
9696
}
9797
}
@@ -161,4 +161,36 @@ function (AggregationValueInterface $value) {
161161
$attributes
162162
);
163163
}
164+
165+
/**
166+
* Get sorted options
167+
*
168+
* @param BucketInterface $bucket
169+
* @param array $optionLabels
170+
* @return array
171+
*/
172+
private function getSortedOptions(BucketInterface $bucket, array $optionLabels): array
173+
{
174+
/**
175+
* Option labels array has been sorted
176+
*/
177+
$options = $optionLabels;
178+
foreach ($bucket->getValues() as $value) {
179+
$metrics = $value->getMetrics();
180+
$optionValue = $metrics['value'];
181+
$optionLabel = $optionLabels[$optionValue] ?? $optionValue;
182+
$options[$optionValue] = $metrics + ['label' => $optionLabel];
183+
}
184+
185+
/**
186+
* Delete options without bucket values
187+
*/
188+
foreach ($options as $optionId => $option) {
189+
if (!is_array($options[$optionId])) {
190+
unset($options[$optionId]);
191+
}
192+
}
193+
194+
return array_values($options);
195+
}
164196
}

dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoriesQuery/CategoryAggregationsTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,17 @@ function ($a) {
5252
$this->assertCount(2, $customAggregation);
5353
$this->assertEquals('test_attribute_2', $customAggregation[0]['attribute_code']);
5454
$this->assertEquals('test_attribute_1', $customAggregation[1]['attribute_code']);
55+
56+
/**
57+
* Check sorting options
58+
*/
59+
$optionsAttribute1 = $customAggregation[0]['options'];
60+
$this->assertCount(3, $optionsAttribute1);
61+
$this->assertEquals('Option 1', $optionsAttribute1[0]['label']);
62+
$this->assertEquals('Option 2', $optionsAttribute1[1]['label']);
63+
$this->assertEquals('Option 3', $optionsAttribute1[2]['label']);
64+
$this->assertEquals(1, $optionsAttribute1[0]['count']);
65+
$this->assertEquals(2, $optionsAttribute1[1]['count']);
66+
$this->assertEquals(3, $optionsAttribute1[2]['count']);
5567
}
5668
}

dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes.php

Lines changed: 64 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
declare(strict_types=1);
77

88
use Magento\Catalog\Api\Data\CategoryInterfaceFactory;
9+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
910
use Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory;
1011
use Magento\Catalog\Api\Data\ProductInterfaceFactory;
1112
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
@@ -18,7 +19,6 @@
1819
use Magento\Eav\Setup\EavSetup;
1920
use Magento\Indexer\Model\Indexer;
2021
use Magento\Indexer\Model\Indexer\Collection;
21-
use Magento\Msrp\Model\Product\Attribute\Source\Type as SourceType;
2222
use Magento\Store\Api\WebsiteRepositoryInterface;
2323
use Magento\TestFramework\Helper\Bootstrap;
2424
use Magento\TestFramework\Helper\CacheCleaner;
@@ -27,7 +27,6 @@
2727

2828
/** @var Config $eavConfig */
2929
$eavConfig = $objectManager->get(Config::class);
30-
3130
/** @var ProductAttributeRepositoryInterface $attributeRepository */
3231
$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class);
3332
/** @var ProductAttributeInterfaceFactory $attributeFactory */
@@ -42,11 +41,13 @@
4241
$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class);
4342
$baseWebsite = $websiteRepository->get('base');
4443

44+
$attributes = [];
4545
for ($i = 1; $i <= 2; $i++) {
46+
$attributeCode = 'test_attribute_' . $i;
4647
$attributeModel = $attributeFactory->create();
4748
$attributeModel->setData(
4849
[
49-
'attribute_code' => 'test_attribute_' . $i,
50+
'attribute_code' => $attributeCode,
5051
'entity_type_id' => $installer->getEntityTypeId(Product::ENTITY),
5152
'is_global' => 1,
5253
'is_user_defined' => 1,
@@ -66,100 +67,95 @@
6667
'frontend_label' => ['Test Attribute ' . $i],
6768
'backend_type' => 'int',
6869
'option' => [
69-
'value' => ['option_0' => ['Option 1'], 'option_1' => ['Option 2']],
70-
'order' => ['option_0' => 1, 'option_1' => 2],
70+
'value' => ['option_1' => ['Option 1'], 'option_2' => ['Option 2'], 'option_3' => ['Option 3']],
71+
'order' => ['option_1' => 1, 'option_2' => 2, 'option_3' => 3],
7172
],
72-
'default' => ['option_0'],
7373
'position' => 3 - $i
7474
]
7575
);
7676
$attribute = $attributeRepository->save($attributeModel);
7777
$installer->addAttributeToGroup(Product::ENTITY, $attributeSetId, $groupId, $attribute->getId());
78+
$attributes[$attributeCode] = $attribute;
7879
}
7980

81+
/** @var ProductAttributeInterface $attribute1 */
82+
$attribute1 = $attributes['test_attribute_1'];
83+
/** @var ProductAttributeInterface $attribute2 */
84+
$attribute2 = $attributes['test_attribute_2'];
85+
8086
CacheCleaner::cleanAll();
8187
$eavConfig->clear();
8288

83-
/** @var ProductRepositoryInterface $productRepository */
84-
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
85-
/** @var ProductInterfaceFactory $productInterfaceFactory */
86-
$productInterfaceFactory = $objectManager->get(ProductInterfaceFactory::class);
87-
88-
/** @var Product $product */
89-
$product = $productInterfaceFactory->create();
90-
$product->setTypeId(Type::TYPE_SIMPLE)
91-
->setAttributeSetId($product->getDefaultAttributeSetId())
92-
->setName('Simple Product1')
93-
->setSku('simple1')
94-
->setTaxClassId('none')
95-
->setDescription('description')
96-
->setShortDescription('short description')
97-
->setOptionsContainer('container1')
98-
->setMsrpDisplayActualPriceType(SourceType::TYPE_IN_CART)
99-
->setPrice(10)
100-
->setWeight(1)
101-
->setMetaTitle('meta title')
102-
->setMetaKeyword('meta keyword')
103-
->setMetaDescription('meta description')
104-
->setVisibility(Visibility::VISIBILITY_BOTH)
105-
->setStatus(Status::STATUS_ENABLED)
106-
->setWebsiteIds([$baseWebsite->getId()])
107-
->setCategoryIds([])
108-
->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
109-
->setSpecialPrice('5.99');
110-
$simple1 = $productRepository->save($product);
111-
112-
/** @var Product $product */
113-
$product = $productInterfaceFactory->create();
114-
$product->setTypeId(Type::TYPE_SIMPLE)
115-
->setAttributeSetId($product->getDefaultAttributeSetId())
116-
->setName('Simple Product2')
117-
->setSku('simple2')
118-
->setTaxClassId('none')
119-
->setDescription('description')
120-
->setShortDescription('short description')
121-
->setOptionsContainer('container1')
122-
->setMsrpDisplayActualPriceType(SourceType::TYPE_ON_GESTURE)
123-
->setPrice(20)
124-
->setWeight(1)
125-
->setMetaTitle('meta title')
126-
->setMetaKeyword('meta keyword')
127-
->setMetaDescription('meta description')
128-
->setVisibility(Visibility::VISIBILITY_BOTH)
129-
->setStatus(Status::STATUS_ENABLED)
130-
->setWebsiteIds([$baseWebsite->getId()])
131-
->setCategoryIds([])
132-
->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
133-
->setSpecialPrice('15.99');
134-
$simple2 = $productRepository->save($product);
135-
13689
/** @var CategoryInterfaceFactory $categoryInterfaceFactory */
13790
$categoryInterfaceFactory = $objectManager->get(CategoryInterfaceFactory::class);
13891

92+
/** @var Magento\Catalog\Model\Category $category */
13993
$category = $categoryInterfaceFactory->create();
14094
$category->isObjectNew(true);
14195
$category->setId(3334)
142-
->setCreatedAt('2014-06-23 09:50:07')
14396
->setName('Category 1')
14497
->setParentId(2)
145-
->setPath('1/2/333')
98+
->setPath('1/2/3334')
14699
->setLevel(2)
147100
->setAvailableSortBy(['position', 'name'])
148101
->setDefaultSortBy('name')
149102
->setIsActive(true)
150-
->setPosition(1)
151-
->setPostedProducts(
152-
[
153-
$simple1->getId() => 10,
154-
$simple2->getId() => 11
155-
]
156-
);
103+
->setPosition(1);
157104
$category->save();
158105

106+
/** @var ProductRepositoryInterface $productRepository */
107+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
108+
/** @var ProductInterfaceFactory $productInterfaceFactory */
109+
$productInterfaceFactory = $objectManager->get(ProductInterfaceFactory::class);
110+
$products = [];
111+
for ($i = 1; $i <= 6; $i++) {
112+
$sku = 'simple' . $i;
113+
/** @var Product $product */
114+
$product = $productInterfaceFactory->create();
115+
$product->setTypeId(Type::TYPE_SIMPLE)
116+
->setAttributeSetId($product->getDefaultAttributeSetId())
117+
->setName('Simple Product ' . $i)
118+
->setSku($sku)
119+
->setUrlKey('simple-product-' . $i)
120+
->setTaxClassId('none')
121+
->setDescription('description')
122+
->setShortDescription('short description')
123+
->setPrice($i * 10)
124+
->setWeight(1)
125+
->setMetaTitle('meta title')
126+
->setMetaKeyword('meta keyword')
127+
->setMetaDescription('meta description')
128+
->setVisibility(Visibility::VISIBILITY_BOTH)
129+
->setStatus(Status::STATUS_ENABLED)
130+
->setWebsiteIds([$baseWebsite->getId()])
131+
->setCategoryIds([$category->getId()])
132+
->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1]);
133+
$product->setData($attribute1->getAttributeCode(), getAttributeOptionValue($attribute1, 'Option 1'));
134+
$optionForSecondAttribute = 'Option ' . ($i === 1 ? 1 : ($i <= 3 ? 2 : 3));
135+
$product->setData($attribute2->getAttributeCode(), getAttributeOptionValue($attribute2, $optionForSecondAttribute));
136+
137+
$products[$sku] = $productRepository->save($product);
138+
}
139+
159140
/** @var Collection $indexerCollection */
160141
$indexerCollection = $objectManager->get(Collection::class);
161142
$indexerCollection->load();
162143
/** @var Indexer $indexer */
163144
foreach ($indexerCollection->getItems() as $indexer) {
164145
$indexer->reindexAll();
165146
}
147+
148+
/**
149+
* @param ProductAttributeInterface $attribute
150+
* @param string $label
151+
* @return int|null
152+
*/
153+
function getAttributeOptionValue(ProductAttributeInterface $attribute, string $label): ?int
154+
{
155+
foreach ($attribute->getOptions() as $option) {
156+
if ($option->getLabel() === $label) {
157+
return (int)$option->getValue();
158+
}
159+
}
160+
return null;
161+
}

dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes_rollback.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
/** @var ProductRepositoryInterface $productRepository */
2424
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
25-
26-
foreach (['simple1', 'simple2'] as $sku) {
25+
for ($i = 1; $i <= 6; $i++) {
26+
$sku = 'simple' . $i;
2727
try {
2828
$product = $productRepository->get($sku, false, null, true);
2929
$productRepository->delete($product);

0 commit comments

Comments
 (0)