Skip to content

Commit 1999a6c

Browse files
committed
ACP2E-948: Product listing GraphQL query limited to total_count 10,000 products only
1 parent 93488e3 commit 1999a6c

File tree

4 files changed

+63
-120
lines changed

4 files changed

+63
-120
lines changed

app/code/Magento/CatalogGraphQl/DataProvider/Product/SearchCriteriaBuilder.php

Lines changed: 54 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -8,103 +8,49 @@
88
namespace Magento\CatalogGraphQl\DataProvider\Product;
99

1010
use Magento\Catalog\Api\Data\EavAttributeInterface;
11-
use Magento\Catalog\Model\Product;
11+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
1212
use Magento\Catalog\Model\Product\Visibility;
13-
use Magento\Eav\Model\Config;
13+
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverFactory;
1414
use Magento\Framework\Api\FilterBuilder;
1515
use Magento\Framework\Api\Search\FilterGroupBuilder;
1616
use Magento\Framework\Api\Search\SearchCriteriaInterface;
1717
use Magento\Framework\Api\SortOrder;
1818
use Magento\Framework\Api\SortOrderBuilder;
1919
use Magento\Framework\App\Config\ScopeConfigInterface;
20-
use Magento\Framework\App\ObjectManager;
2120
use Magento\Framework\Exception\LocalizedException;
22-
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\Builder;
21+
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\ArgumentApplierPool;
2322
use Magento\Framework\Search\Request\Config as SearchConfig;
2423

2524
/**
2625
* Build search criteria
2726
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2827
*/
29-
3028
class SearchCriteriaBuilder
3129
{
3230
/**
33-
* @var ScopeConfigInterface
34-
*/
35-
private $scopeConfig;
36-
37-
/**
38-
* @var FilterBuilder
39-
*/
40-
private $filterBuilder;
41-
42-
/**
43-
* @var FilterGroupBuilder
44-
*/
45-
private $filterGroupBuilder;
46-
47-
/**
48-
* @var Builder
49-
*/
50-
private $builder;
51-
52-
/**
53-
* @var Visibility
54-
*/
55-
private $visibility;
56-
57-
/**
58-
* @var SortOrderBuilder
59-
*/
60-
private $sortOrderBuilder;
61-
62-
/**
63-
* @var Config
64-
*/
65-
private Config $eavConfig;
66-
67-
/**
68-
* @var SearchConfig
69-
*/
70-
private SearchConfig $searchConfig;
71-
72-
/**
73-
* @var RequestDataBuilder|mixed
74-
*/
75-
private RequestDataBuilder $localData;
76-
77-
/**
78-
* @param Builder $builder
7931
* @param ScopeConfigInterface $scopeConfig
8032
* @param FilterBuilder $filterBuilder
8133
* @param FilterGroupBuilder $filterGroupBuilder
8234
* @param Visibility $visibility
83-
* @param SortOrderBuilder|null $sortOrderBuilder
84-
* @param Config|null $eavConfig
85-
* @param SearchConfig|null $searchConfig
86-
* @param RequestDataBuilder|null $localData
35+
* @param SortOrderBuilder $sortOrderBuilder
36+
* @param ProductAttributeRepositoryInterface $productAttributeRepository
37+
* @param SearchConfig $searchConfig
38+
* @param RequestDataBuilder $localData
39+
* @param SearchCriteriaResolverFactory $criteriaResolverFactory
40+
* @param ArgumentApplierPool $argumentApplierPool
8741
*/
8842
public function __construct(
89-
Builder $builder,
90-
ScopeConfigInterface $scopeConfig,
91-
FilterBuilder $filterBuilder,
92-
FilterGroupBuilder $filterGroupBuilder,
93-
Visibility $visibility,
94-
SortOrderBuilder $sortOrderBuilder = null,
95-
Config $eavConfig = null,
96-
SearchConfig $searchConfig = null,
97-
RequestDataBuilder $localData = null,
43+
private readonly ScopeConfigInterface $scopeConfig,
44+
private readonly FilterBuilder $filterBuilder,
45+
private readonly FilterGroupBuilder $filterGroupBuilder,
46+
private readonly Visibility $visibility,
47+
private readonly SortOrderBuilder $sortOrderBuilder,
48+
private readonly ProductAttributeRepositoryInterface $productAttributeRepository,
49+
private readonly SearchConfig $searchConfig,
50+
private readonly RequestDataBuilder $localData,
51+
private readonly SearchCriteriaResolverFactory $criteriaResolverFactory,
52+
private readonly ArgumentApplierPool $argumentApplierPool,
9853
) {
99-
$this->scopeConfig = $scopeConfig;
100-
$this->filterBuilder = $filterBuilder;
101-
$this->filterGroupBuilder = $filterGroupBuilder;
102-
$this->builder = $builder;
103-
$this->visibility = $visibility;
104-
$this->sortOrderBuilder = $sortOrderBuilder ?? ObjectManager::getInstance()->get(SortOrderBuilder::class);
105-
$this->eavConfig = $eavConfig ?? ObjectManager::getInstance()->get(Config::class);
106-
$this->searchConfig = $searchConfig ?? ObjectManager::getInstance()->get(SearchConfig::class);
107-
$this->localData = $localData ?? ObjectManager::getInstance()->get(RequestDataBuilder::class);
10854
}
10955

11056
/**
@@ -117,45 +63,41 @@ public function __construct(
11763
*/
11864
public function build(array $args, bool $includeAggregation): SearchCriteriaInterface
11965
{
120-
$partialMatchFilters = [];
66+
$isSearch = isset($args['search']);
67+
$requestName = $includeAggregation ? 'graphql_product_search_with_aggregation' : 'graphql_product_search';
68+
12169
if (isset($args['filter'])) {
12270
$partialMatchFilters = $this->getPartialMatchFilters($args);
71+
if (count($partialMatchFilters)) {
72+
$this->updateMatchTypeRequestConfig($requestName, $partialMatchFilters);
73+
}
12374
$args = $this->removeMatchTypeFromArguments($args);
12475
}
125-
$searchCriteria = $this->builder->build('products', $args);
126-
$isSearch = isset($args['search']);
127-
$this->updateRangeFilters($searchCriteria);
128-
if ($includeAggregation) {
129-
$attributeData = $this->eavConfig->getAttribute(Product::ENTITY, 'price');
130-
$priceOptions = $attributeData->getData();
13176

132-
if ($priceOptions['is_filterable'] != 0) {
133-
$this->preparePriceAggregation($searchCriteria);
77+
$searchCriteria = $this->criteriaResolverFactory->create(
78+
[
79+
'searchRequestName' => $requestName,
80+
'currentPage' => $args['currentPage'],
81+
'size' => $args['pageSize'],
82+
]
83+
)->resolve();
84+
foreach ($args as $argumentName => $argument) {
85+
if ($this->argumentApplierPool->hasApplier($argumentName)) {
86+
$argumentApplier = $this->argumentApplierPool->getApplier($argumentName);
87+
$argumentApplier->applyArgument($searchCriteria, 'products', $argumentName, $argument);
13488
}
135-
$requestName = 'graphql_product_search_with_aggregation';
136-
} else {
137-
$requestName = 'graphql_product_search';
138-
}
139-
$searchCriteria->setRequestName($requestName);
140-
141-
if (count($partialMatchFilters)) {
142-
$this->updateMatchTypeRequestConfig($requestName, $partialMatchFilters);
14389
}
144-
90+
$this->updateRangeFilters($searchCriteria);
91+
$this->preparePriceAggregation($searchCriteria, $includeAggregation);
14592
if ($isSearch) {
14693
$this->addFilter($searchCriteria, 'search_term', $args['search']);
14794
}
148-
14995
if (!$searchCriteria->getSortOrders()) {
150-
$this->addDefaultSortOrder($searchCriteria, $args, $isSearch);
96+
$this->addDefaultSortOrder($searchCriteria, $args);
15197
}
152-
15398
$this->addEntityIdSort($searchCriteria);
15499
$this->addVisibilityFilter($searchCriteria, $isSearch, !empty($args['filter']['category_id']));
155100

156-
$searchCriteria->setCurrentPage($args['currentPage'] - 1);
157-
$searchCriteria->setPageSize($args['pageSize']);
158-
159101
return $searchCriteria;
160102
}
161103

@@ -164,7 +106,6 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte
164106
*
165107
* @param string $requestName
166108
* @param array $partialMatchFilters
167-
*
168109
* @return void
169110
*/
170111
private function updateMatchTypeRequestConfig(string $requestName, array $partialMatchFilters): void
@@ -184,7 +125,6 @@ private function updateMatchTypeRequestConfig(string $requestName, array $partia
184125
* Check if and what type of match_type value was requested
185126
*
186127
* @param array $args
187-
*
188128
* @return array
189129
*/
190130
private function getPartialMatchFilters(array $args): array
@@ -202,7 +142,6 @@ private function getPartialMatchFilters(array $args): array
202142
* Remove the match_type to avoid search criteria containing it
203143
*
204144
* @param array $args
205-
*
206145
* @return array
207146
*/
208147
private function removeMatchTypeFromArguments(array $args): array
@@ -264,10 +203,21 @@ private function addEntityIdSort(SearchCriteriaInterface $searchCriteria): void
264203
* Prepare price aggregation algorithm
265204
*
266205
* @param SearchCriteriaInterface $searchCriteria
206+
* @param bool $includeAggregation
267207
* @return void
268208
*/
269-
private function preparePriceAggregation(SearchCriteriaInterface $searchCriteria): void
209+
private function preparePriceAggregation(SearchCriteriaInterface $searchCriteria, bool $includeAggregation): void
270210
{
211+
if (!$includeAggregation) {
212+
return;
213+
}
214+
215+
$attributeData = $this->productAttributeRepository->get('price');
216+
$priceOptions = $attributeData->getData();
217+
if ((int) $priceOptions['is_filterable'] === 0) {
218+
return;
219+
}
220+
271221
$priceRangeCalculation = $this->scopeConfig->getValue(
272222
\Magento\Catalog\Model\Layer\Filter\Dynamic\AlgorithmFactory::XML_PATH_RANGE_CALCULATION,
273223
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
@@ -308,18 +258,17 @@ private function addFilter(
308258
*
309259
* @param SearchCriteriaInterface $searchCriteria
310260
* @param array $args
311-
* @param bool $isSearch
312261
*/
313-
private function addDefaultSortOrder(SearchCriteriaInterface $searchCriteria, array $args, $isSearch = false): void
262+
private function addDefaultSortOrder(SearchCriteriaInterface $searchCriteria, array $args): void
314263
{
315264
$defaultSortOrder = [];
316-
if ($isSearch) {
265+
if (isset($args['search'])) {
317266
$defaultSortOrder[] = $this->sortOrderBuilder
318267
->setField('relevance')
319268
->setDirection(SortOrder::SORT_DESC)
320269
->create();
321270
} else {
322-
$categoryIdFilter = isset($args['filter']['category_id']) ? $args['filter']['category_id'] : false;
271+
$categoryIdFilter = $args['filter']['category_id'] ?? false;
323272
if ($categoryIdFilter) {
324273
if (!is_array($categoryIdFilter[array_key_first($categoryIdFilter)])
325274
|| count($categoryIdFilter[array_key_first($categoryIdFilter)]) <= 1

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ public function getResult(
146146
'totalCount' => $totalCount,
147147
'productsSearchResult' => $productArray,
148148
'searchAggregation' => $itemsResults->getAggregations(),
149-
'pageSize' => $searchCriteria->getPageSize(),
150-
'currentPage' => $searchCriteria->getCurrentPage() + 1, //search criteria pagination starts with 0
149+
'pageSize' => $args['pageSize'],
150+
'currentPage' => $args['currentPage'],
151151
'totalPages' => $totalPages,
152152
'suggestions' => $suggestions,
153153
]

app/code/Magento/Elasticsearch/Model/ResourceModel/Fulltext/Collection/SearchCriteriaResolver.php

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6-
76
namespace Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection;
87

98
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverInterface;
10-
use Magento\Framework\Data\Collection;
119
use Magento\Framework\Api\Search\SearchCriteriaBuilder;
1210
use Magento\Framework\Api\Search\SearchCriteria;
1311

@@ -23,11 +21,6 @@ class SearchCriteriaResolver implements SearchCriteriaResolverInterface
2321
*/
2422
private $builder;
2523

26-
/**
27-
* @var Collection
28-
*/
29-
private $collection;
30-
3124
/**
3225
* @var string
3326
*/
@@ -39,7 +32,7 @@ class SearchCriteriaResolver implements SearchCriteriaResolverInterface
3932
private $size;
4033

4134
/**
42-
* @var array
35+
* @var array|null
4336
*/
4437
private $orders;
4538

@@ -49,24 +42,20 @@ class SearchCriteriaResolver implements SearchCriteriaResolverInterface
4942
private $currentPage;
5043

5144
/**
52-
* SearchCriteriaResolver constructor.
5345
* @param SearchCriteriaBuilder $builder
54-
* @param Collection $collection
5546
* @param string $searchRequestName
5647
* @param int $currentPage
5748
* @param int $size
58-
* @param array $orders
49+
* @param array|null $orders
5950
*/
6051
public function __construct(
6152
SearchCriteriaBuilder $builder,
62-
Collection $collection,
6353
string $searchRequestName,
6454
int $currentPage,
6555
int $size,
6656
?array $orders
6757
) {
6858
$this->builder = $builder;
69-
$this->collection = $collection;
7059
$this->searchRequestName = $searchRequestName;
7160
$this->currentPage = $currentPage;
7261
$this->size = $size;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,4 +418,9 @@
418418
<argument name="sortExpressionBuilder" xsi:type="object">Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\ExpressionBuilder</argument>
419419
</arguments>
420420
</type>
421+
<type name="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverFactory">
422+
<arguments>
423+
<argument name="instanceName" xsi:type="string">Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolver</argument>
424+
</arguments>
425+
</type>
421426
</config>

0 commit comments

Comments
 (0)