Skip to content

Commit c7fdfd3

Browse files
committed
#33387: fix GraphQl products query layered navigation category child
1 parent 44dc3cd commit c7fdfd3

File tree

4 files changed

+339
-1
lines changed

4 files changed

+339
-1
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogGraphQl\Model\Resolver\Products\Query;
9+
10+
use Magento\Catalog\Model\CategoryRepository;
11+
use Magento\Framework\Api\Search\AggregationValueInterface;
12+
use Magento\Framework\Exception\NoSuchEntityException;
13+
use Magento\Framework\Search\Response\Aggregation;
14+
use Magento\Framework\Search\Response\AggregationFactory;
15+
use Magento\Framework\Search\Response\Bucket;
16+
use Magento\Framework\Search\Response\BucketFactory;
17+
use Magento\Store\Model\StoreManagerInterface;
18+
19+
/**
20+
* Resolve category aggregation.
21+
*/
22+
class ResolveCategoryAggregation
23+
{
24+
/**
25+
* @var string
26+
*/
27+
public const CATEGORY_BUCKET = 'category_bucket';
28+
29+
/**
30+
* @var string
31+
*/
32+
private const BUCKETS = 'buckets';
33+
34+
/**
35+
* @var AggregationFactory
36+
*/
37+
private $aggregationFactory;
38+
39+
/**
40+
* @var BucketFactory
41+
*/
42+
private $bucketFactory;
43+
44+
/**
45+
* @var StoreManagerInterface
46+
*/
47+
private $storeManager;
48+
49+
/**
50+
* @var CategoryRepository
51+
*/
52+
private $categoryRepository;
53+
54+
/**
55+
* @var array
56+
*/
57+
private $resolvedChildrenIds = [];
58+
59+
/**
60+
* @param AggregationFactory $aggregationFactory
61+
* @param BucketFactory $bucketFactory
62+
* @param StoreManagerInterface $storeManager
63+
* @param CategoryRepository $categoryRepository
64+
*/
65+
public function __construct(
66+
AggregationFactory $aggregationFactory,
67+
BucketFactory $bucketFactory,
68+
StoreManagerInterface $storeManager,
69+
CategoryRepository $categoryRepository
70+
) {
71+
$this->aggregationFactory = $aggregationFactory;
72+
$this->bucketFactory = $bucketFactory;
73+
$this->storeManager = $storeManager;
74+
$this->categoryRepository = $categoryRepository;
75+
}
76+
77+
/**
78+
* Get resolved category aggregation.
79+
*
80+
* @param array $categoryFilter
81+
* @param Bucket[] $bucketList
82+
*
83+
* @return Aggregation
84+
*/
85+
public function getResolvedCategoryAggregation(array $categoryFilter, array $bucketList): Aggregation
86+
{
87+
$categoryBucket = $bucketList[self::CATEGORY_BUCKET] ?? [];
88+
$values = $categoryBucket->getValues();
89+
$condition = array_key_first($categoryFilter);
90+
$searchableCategoryValue = $categoryFilter[$condition] ?? 0;
91+
92+
if (!$searchableCategoryValue || empty($values)) {
93+
return $this->aggregationFactory->create([self::BUCKETS => $bucketList]);
94+
}
95+
96+
$resolvedBucketList = $bucketList;
97+
98+
try {
99+
if (!is_array($searchableCategoryValue)) {
100+
$resolvedValues = $this->getValidCategories((int) $searchableCategoryValue, $values);
101+
} else {
102+
$categoryResolvedValues = [];
103+
104+
foreach ($searchableCategoryValue as $categoryId) {
105+
$categoryResolvedValues[] = $this->getValidCategories((int) $categoryId, $values);
106+
}
107+
108+
$resolvedValues = call_user_func_array('array_merge', $categoryResolvedValues);;
109+
}
110+
} catch (NoSuchEntityException $e) {
111+
return $this->aggregationFactory->create([self::BUCKETS => $bucketList]);
112+
}
113+
114+
$resolvedCategoryBucket = $this->bucketFactory->create(
115+
[
116+
'name' => self::CATEGORY_BUCKET,
117+
'values' => $resolvedValues
118+
]
119+
);
120+
121+
$resolvedBucketList[self::CATEGORY_BUCKET] = $resolvedCategoryBucket;
122+
123+
return $this->aggregationFactory->create([self::BUCKETS => $resolvedBucketList]);
124+
}
125+
126+
/**
127+
* Check is valid searchable category children.
128+
*
129+
* @param int $searchableCategoryId
130+
* @param AggregationValueInterface[] $aggregationValues
131+
*
132+
* @return AggregationValueInterface[]
133+
*
134+
* @throws NoSuchEntityException
135+
*/
136+
private function getValidCategories(int $searchableCategoryId, array $aggregationValues): array
137+
{
138+
$stareId = (int) $this->storeManager->getStore()->getId();
139+
$searchableCategory = $this->categoryRepository->get($searchableCategoryId, $stareId);
140+
$childrenList = $searchableCategory->getChildrenCategories();
141+
$resolvedList = [];
142+
$validChildIdList = [];
143+
144+
foreach ($childrenList as $child) {
145+
if (!$child->getIsActive()) {
146+
continue;
147+
}
148+
149+
$validChildIdList[] = $child->getId();
150+
}
151+
152+
foreach ($aggregationValues as $bucketValue) {
153+
$childCategoryId = (int) $bucketValue->getValue();
154+
155+
if (!in_array($childCategoryId, $validChildIdList) ||
156+
in_array($childCategoryId, $this->resolvedChildrenIds)
157+
) {
158+
continue;
159+
}
160+
161+
$resolvedList[] = $bucketValue;
162+
$this->resolvedChildrenIds[] = $childCategoryId;
163+
}
164+
165+
return $resolvedList;
166+
}
167+
}

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Query/Search.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ class Search implements ProductQueryInterface
5555
*/
5656
private $productsProvider;
5757

58+
/**
59+
* @var ResolveCategoryAggregation
60+
*/
61+
private $resolveCategoryAggregation;
62+
5863
/**
5964
* @var SearchCriteriaBuilder
6065
*/
@@ -68,6 +73,7 @@ class Search implements ProductQueryInterface
6873
* @param ProductSearch $productsProvider
6974
* @param SearchCriteriaBuilder $searchCriteriaBuilder
7075
* @param ArgumentsProcessorInterface|null $argsSelection
76+
* @param ResolveCategoryAggregation $resolveCategoryAggregation
7177
*/
7278
public function __construct(
7379
SearchInterface $search,
@@ -76,6 +82,7 @@ public function __construct(
7682
FieldSelection $fieldSelection,
7783
ProductSearch $productsProvider,
7884
SearchCriteriaBuilder $searchCriteriaBuilder,
85+
ResolveCategoryAggregation $resolveCategoryAggregation,
7986
ArgumentsProcessorInterface $argsSelection = null
8087
) {
8188
$this->search = $search;
@@ -84,6 +91,7 @@ public function __construct(
8491
$this->fieldSelection = $fieldSelection;
8592
$this->productsProvider = $productsProvider;
8693
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
94+
$this->resolveCategoryAggregation = $resolveCategoryAggregation;
8795
$this->argsSelection = $argsSelection ?: ObjectManager::getInstance()
8896
->get(ArgumentsProcessorInterface::class);
8997
}
@@ -94,7 +102,9 @@ public function __construct(
94102
* @param array $args
95103
* @param ResolveInfo $info
96104
* @param ContextInterface $context
105+
*
97106
* @return SearchResult
107+
*
98108
* @throws GraphQlInputException
99109
*/
100110
public function getResult(
@@ -124,6 +134,17 @@ public function getResult(
124134

125135
$totalPages = $realPageSize ? ((int)ceil($searchResults->getTotalCount() / $realPageSize)) : 0;
126136

137+
$aggregations = $itemsResults->getAggregations();
138+
$bucketList = $aggregations->getBuckets();
139+
$categoryFilter = $args['filter']['category_id'] ?? [];
140+
141+
if (!empty($categoryFilter) && isset($bucketList[ResolveCategoryAggregation::CATEGORY_BUCKET])) {
142+
$aggregations = $this->resolveCategoryAggregation->getResolvedCategoryAggregation(
143+
$categoryFilter,
144+
$bucketList
145+
);
146+
}
147+
127148
$productArray = [];
128149
/** @var \Magento\Catalog\Model\Product $product */
129150
foreach ($searchResults->getItems() as $product) {
@@ -135,7 +156,7 @@ public function getResult(
135156
[
136157
'totalCount' => $searchResults->getTotalCount(),
137158
'productsSearchResult' => $productArray,
138-
'searchAggregation' => $itemsResults->getAggregations(),
159+
'searchAggregation' => $aggregations,
139160
'pageSize' => $realPageSize,
140161
'currentPage' => $realCurrentPage,
141162
'totalPages' => $totalPages,
@@ -148,7 +169,10 @@ public function getResult(
148169
*
149170
* @param array $args
150171
* @param ResolveInfo $info
172+
*
151173
* @return SearchCriteriaInterface
174+
*
175+
* @throws GraphQlInputException
152176
*/
153177
private function buildSearchCriteria(array $args, ResolveInfo $info): SearchCriteriaInterface
154178
{

app/code/Magento/CatalogGraphQl/etc/di.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@
8585
</arguments>
8686
</type>
8787

88+
<type name="Magento\CatalogGraphQl\Model\Resolver\Products\Query\Search">
89+
<arguments>
90+
<argument name="resolveCategoryAggregation" xsi:type="object">Magento\CatalogGraphQl\Model\Resolver\Products\Query\ResolveCategoryAggregation\Proxy</argument>
91+
</arguments>
92+
</type>
93+
8894
<type name="Magento\Framework\Search\Request\Config\FilesystemReader">
8995
<plugin name="productAttributesDynamicFields" type="Magento\CatalogGraphQl\Plugin\Search\Request\ConfigReader" />
9096
</type>

0 commit comments

Comments
 (0)