diff --git a/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php b/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php index d46776bfe498e..5f8a332915bdd 100644 --- a/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php +++ b/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php @@ -33,8 +33,9 @@ class AttributeOptionProvider /** * @param ResourceConnection $resourceConnection */ - public function __construct(ResourceConnection $resourceConnection) - { + public function __construct( + ResourceConnection $resourceConnection + ) { $this->resourceConnection = $resourceConnection; } @@ -62,6 +63,7 @@ public function getOptions(array $optionIds, ?int $storeId, array $attributeCode 'attribute_id' => 'a.attribute_id', 'attribute_code' => 'a.attribute_code', 'attribute_label' => 'a.frontend_label', + 'frontend_input' => 'a.frontend_input', ] ) ->joinLeft( @@ -126,8 +128,8 @@ private function formatResult(\Magento\Framework\DB\Select $select): array $result[$option['attribute_code']] = [ 'attribute_id' => $option['attribute_id'], 'attribute_code' => $option['attribute_code'], - 'attribute_label' => $option['attribute_store_label'] - ? $option['attribute_store_label'] : $option['attribute_label'], + 'attribute_label' => $option['attribute_store_label'] ?: $option['attribute_label'], + 'frontend_input' => $option['frontend_input'], 'options' => [], ]; } diff --git a/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php b/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php index 5fce0fcdf3ca2..b358c9a35f707 100644 --- a/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php +++ b/app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php @@ -8,11 +8,12 @@ namespace Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\Builder; use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\AttributeOptionProvider; +use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\Formatter\LayerFormatter; use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilderInterface; +use Magento\Config\Model\Config\Source\Yesno; use Magento\Framework\Api\Search\AggregationInterface; use Magento\Framework\Api\Search\AggregationValueInterface; use Magento\Framework\Api\Search\BucketInterface; -use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\Formatter\LayerFormatter; /** * @inheritdoc @@ -49,19 +50,27 @@ class Attribute implements LayerBuilderInterface self::CATEGORY_BUCKET ]; + /** + * @var Yesno + */ + private $yesNo; + /** * @param AttributeOptionProvider $attributeOptionProvider * @param LayerFormatter $layerFormatter + * @param Yesno $yesNo * @param array $bucketNameFilter */ public function __construct( AttributeOptionProvider $attributeOptionProvider, LayerFormatter $layerFormatter, + Yesno $yesNo, $bucketNameFilter = [] ) { $this->attributeOptionProvider = $attributeOptionProvider; $this->layerFormatter = $layerFormatter; $this->bucketNameFilter = \array_merge($this->bucketNameFilter, $bucketNameFilter); + $this->yesNo = $yesNo; } /** @@ -89,7 +98,7 @@ public function build(AggregationInterface $aggregation, ?int $storeId): array foreach ($bucket->getValues() as $value) { $metrics = $value->getMetrics(); $result[$bucketName]['options'][] = $this->layerFormatter->buildItem( - $attribute['options'][$metrics['value']] ?? $metrics['value'], + $this->getOptionLabel($attribute, $metrics), $metrics['value'], $metrics['count'] ); @@ -99,6 +108,23 @@ public function build(AggregationInterface $aggregation, ?int $storeId): array return $result; } + /** + * Get option label + * + * @param array $attribute + * @param array $metrics + * @return mixed + */ + private function getOptionLabel(array $attribute, array $metrics) + { + if ($attribute['frontend_input'] === 'boolean') { + $yesNoOptions = $this->yesNo->toArray(); + return $yesNoOptions[$metrics['value']]; + } + + return $attribute['options'][$metrics['value']] ?? $metrics['value']; + } + /** * Get attribute buckets excluding specified bucket names * diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Aggregations.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Aggregations.php index cc76855cc6d20..4d70b64706c73 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Aggregations.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Aggregations.php @@ -20,11 +20,6 @@ */ class Aggregations implements ResolverInterface { - /** - * @var Layer\DataProvider\Filters - */ - private $filtersDataProvider; - /** * @var LayerBuilder */ @@ -36,16 +31,13 @@ class Aggregations implements ResolverInterface private $priceCurrency; /** - * @param \Magento\CatalogGraphQl\Model\Resolver\Layer\DataProvider\Filters $filtersDataProvider * @param LayerBuilder $layerBuilder * @param PriceCurrency $priceCurrency */ public function __construct( - \Magento\CatalogGraphQl\Model\Resolver\Layer\DataProvider\Filters $filtersDataProvider, LayerBuilder $layerBuilder, PriceCurrency $priceCurrency = null ) { - $this->filtersDataProvider = $filtersDataProvider; $this->layerBuilder = $layerBuilder; $this->priceCurrency = $priceCurrency ?: ObjectManager::getInstance()->get(PriceCurrency::class); } @@ -60,7 +52,7 @@ public function resolve( array $value = null, array $args = null ) { - if (!isset($value['layer_type']) || !isset($value['search_result'])) { + if (!isset($value['layer_type'], $value['search_result'])) { return null; } @@ -82,8 +74,8 @@ public function resolve( } } return $results; - } else { - return []; } + + return []; } } diff --git a/app/code/Magento/CatalogGraphQl/composer.json b/app/code/Magento/CatalogGraphQl/composer.json index 463f974056749..d7e8e653205f3 100644 --- a/app/code/Magento/CatalogGraphQl/composer.json +++ b/app/code/Magento/CatalogGraphQl/composer.json @@ -13,7 +13,8 @@ "magento/module-eav-graph-ql": "*", "magento/module-catalog-search": "*", "magento/framework": "*", - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "*", + "magento/module-config": "*" }, "suggest": { "magento/module-graph-ql-cache": "*", diff --git a/app/code/Magento/CatalogGraphQl/etc/module.xml b/app/code/Magento/CatalogGraphQl/etc/module.xml index 87696c129a714..938a9755b6c29 100644 --- a/app/code/Magento/CatalogGraphQl/etc/module.xml +++ b/app/code/Magento/CatalogGraphQl/etc/module.xml @@ -15,6 +15,7 @@ + diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchAggregationsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchAggregationsTest.php index 41a5d41f2641d..8e0baf10e720d 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchAggregationsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchAggregationsTest.php @@ -14,68 +14,66 @@ class ProductSearchAggregationsTest extends GraphQlAbstract /** * @magentoApiDataFixture Magento/Catalog/_files/products_with_boolean_attribute.php */ - public function testAggregationBooleanAttribute() + public function testAggregationBooleanAttribute(): void { - $this->markTestSkipped('MC-22184: Elasticsearch returns incorrect aggregation options for booleans'); - $query = $this->getGraphQlQuery( '"search_product_1", "search_product_2", "search_product_3", "search_product_4" ,"search_product_5"' ); $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertArrayHasKey('items', $result['products']); - $this->assertCount(5, $result['products']['items']); - $this->assertArrayHasKey('aggregations', $result['products']); + self::assertArrayNotHasKey('errors', $result); + self::assertArrayHasKey('items', $result['products']); + self::assertCount(5, $result['products']['items']); + self::assertArrayHasKey('aggregations', $result['products']); $booleanAggregation = array_filter( $result['products']['aggregations'], function ($a) { - return $a['attribute_code'] == 'boolean_attribute'; + return $a['attribute_code'] === 'boolean_attribute'; } ); - $this->assertNotEmpty($booleanAggregation); + self::assertNotEmpty($booleanAggregation); $booleanAggregation = reset($booleanAggregation); - $this->assertEquals('Boolean Attribute', $booleanAggregation['label']); - $this->assertEquals('boolean_attribute', $booleanAggregation['attribute_code']); - $this->assertContainsEquals(['label' => '1', 'value'=> '1', 'count' => '3'], $booleanAggregation['options']); + self::assertEquals('Boolean Attribute', $booleanAggregation['label']); + self::assertEquals('boolean_attribute', $booleanAggregation['attribute_code']); + self::assertContainsEquals(['label' => 'Yes', 'value'=> '1', 'count' => '3'], $booleanAggregation['options']); - $this->assertEquals(2, $booleanAggregation['count']); - $this->assertCount(2, $booleanAggregation['options']); - $this->assertContainsEquals(['label' => '0', 'value'=> '0', 'count' => '2'], $booleanAggregation['options']); + self::assertEquals(2, $booleanAggregation['count']); + self::assertCount(2, $booleanAggregation['options']); + self::assertContainsEquals(['label' => 'No', 'value'=> '0', 'count' => '2'], $booleanAggregation['options']); } /** * @magentoApiDataFixture Magento/Catalog/_files/products_for_search.php */ - public function testAggregationPriceRanges() + public function testAggregationPriceRanges(): void { $query = $this->getGraphQlQuery( '"search_product_1", "search_product_2", "search_product_3", "search_product_4" ,"search_product_5"' ); $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertArrayHasKey('aggregations', $result['products']); + self::assertArrayNotHasKey('errors', $result); + self::assertArrayHasKey('aggregations', $result['products']); $priceAggregation = array_filter( $result['products']['aggregations'], function ($a) { - return $a['attribute_code'] == 'price'; + return $a['attribute_code'] === 'price'; } ); - $this->assertNotEmpty($priceAggregation); + self::assertNotEmpty($priceAggregation); $priceAggregation = reset($priceAggregation); - $this->assertEquals('Price', $priceAggregation['label']); - $this->assertEquals(4, $priceAggregation['count']); + self::assertEquals('Price', $priceAggregation['label']); + self::assertEquals(4, $priceAggregation['count']); $expectedOptions = [ ['label' => '10-20', 'value'=> '10_20', 'count' => '2'], ['label' => '20-30', 'value'=> '20_30', 'count' => '1'], ['label' => '30-40', 'value'=> '30_40', 'count' => '1'], ['label' => '40-50', 'value'=> '40_50', 'count' => '1'] ]; - $this->assertEquals($expectedOptions, $priceAggregation['options']); + self::assertEquals($expectedOptions, $priceAggregation['options']); } /** @@ -83,39 +81,48 @@ function ($a) { * @magentoApiDataFixture Magento/Directory/_files/usd_cny_rate.php * @magentoConfigFixture default_store currency/options/allow CNY,USD */ - public function testAggregationPriceRangesWithCurrencyHeader() + public function testAggregationPriceRangesWithCurrencyHeader(): void { $headerMap['Content-Currency'] = 'CNY'; $query = $this->getGraphQlQuery( '"search_product_1", "search_product_2", "search_product_3", "search_product_4" ,"search_product_5"' ); $result = $this->graphQlQuery($query, [], '', $headerMap); - $this->assertArrayNotHasKey('errors', $result); - $this->assertArrayHasKey('aggregations', $result['products']); + self::assertArrayNotHasKey('errors', $result); + self::assertArrayHasKey('aggregations', $result['products']); $priceAggregation = array_filter( $result['products']['aggregations'], function ($a) { - return $a['attribute_code'] == 'price'; + return $a['attribute_code'] === 'price'; } ); - $this->assertNotEmpty($priceAggregation); + self::assertNotEmpty($priceAggregation); $priceAggregation = reset($priceAggregation); - $this->assertEquals('Price', $priceAggregation['label']); - $this->assertEquals(4, $priceAggregation['count']); + self::assertEquals('Price', $priceAggregation['label']); + self::assertEquals(4, $priceAggregation['count']); $expectedOptions = [ ['label' => '70-140', 'value'=> '70_140', 'count' => '2'], ['label' => '140-210', 'value'=> '140_210', 'count' => '1'], ['label' => '210-280', 'value'=> '210_280', 'count' => '1'], ['label' => '280-350', 'value'=> '280_350', 'count' => '1'] ]; - $this->assertEquals($expectedOptions, $priceAggregation['options']); + self::assertEquals($expectedOptions, $priceAggregation['options']); } - private function getGraphQlQuery(string $skus) + /** + * Get query + * + * @param string $skus + * @return string + */ + private function getGraphQlQuery(string $skus): string { return <<requireDataFixture('Magento/Catalog/_files/products_for_search.php'); @@ -28,11 +29,11 @@ $product->setBooleanAttribute(0); $productRepository->save($product); } -CacheCleaner::cleanAll(); -/** @var \Magento\Indexer\Model\Indexer\Collection $indexerCollection */ -$indexerCollection = $objectManager->get(\Magento\Indexer\Model\Indexer\Collection::class); + +/** @var Collection $indexerCollection */ +$indexerCollection = $objectManager->get(Collection::class); $indexerCollection->load(); -/** @var \Magento\Indexer\Model\Indexer $indexer */ +/** @var Indexer $indexer */ foreach ($indexerCollection->getItems() as $indexer) { $indexer->reindexAll(); }