88namespace Magento \CatalogGraphQl \DataProvider \Product ;
99
1010use Magento \Catalog \Api \Data \EavAttributeInterface ;
11- use Magento \Catalog \Model \ Product ;
11+ use Magento \Catalog \Api \ ProductAttributeRepositoryInterface ;
1212use Magento \Catalog \Model \Product \Visibility ;
13- use Magento \Eav \Model \Config ;
13+ use Magento \CatalogSearch \Model \ResourceModel \ Fulltext \ Collection \ SearchCriteriaResolverFactory ;
1414use Magento \Framework \Api \FilterBuilder ;
1515use Magento \Framework \Api \Search \FilterGroupBuilder ;
1616use Magento \Framework \Api \Search \SearchCriteriaInterface ;
1717use Magento \Framework \Api \SortOrder ;
1818use Magento \Framework \Api \SortOrderBuilder ;
1919use Magento \Framework \App \Config \ScopeConfigInterface ;
20- use Magento \Framework \App \ObjectManager ;
2120use Magento \Framework \Exception \LocalizedException ;
22- use Magento \Framework \GraphQl \Query \Resolver \Argument \SearchCriteria \Builder ;
21+ use Magento \Framework \GraphQl \Query \Resolver \Argument \SearchCriteria \ArgumentApplierPool ;
2322use Magento \Framework \Search \Request \Config as SearchConfig ;
2423
2524/**
2625 * Build search criteria
2726 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2827 */
29-
3028class 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
41+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
8742 */
8843 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 ,
44+ private readonly ScopeConfigInterface $ scopeConfig ,
45+ private readonly FilterBuilder $ filterBuilder ,
46+ private readonly FilterGroupBuilder $ filterGroupBuilder ,
47+ private readonly Visibility $ visibility ,
48+ private readonly SortOrderBuilder $ sortOrderBuilder ,
49+ private readonly ProductAttributeRepositoryInterface $ productAttributeRepository ,
50+ private readonly SearchConfig $ searchConfig ,
51+ private readonly RequestDataBuilder $ localData ,
52+ private readonly SearchCriteriaResolverFactory $ criteriaResolverFactory ,
53+ private readonly ArgumentApplierPool $ argumentApplierPool ,
9854 ) {
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);
10855 }
10956
11057 /**
@@ -117,45 +64,42 @@ public function __construct(
11764 */
11865 public function build (array $ args , bool $ includeAggregation ): SearchCriteriaInterface
11966 {
120- $ partialMatchFilters = [];
67+ $ isSearch = isset ($ args ['search ' ]);
68+ $ requestName = $ includeAggregation ? 'graphql_product_search_with_aggregation ' : 'graphql_product_search ' ;
69+
12170 if (isset ($ args ['filter ' ])) {
12271 $ partialMatchFilters = $ this ->getPartialMatchFilters ($ args );
72+ if (count ($ partialMatchFilters )) {
73+ $ this ->updateMatchTypeRequestConfig ($ requestName , $ partialMatchFilters );
74+ }
12375 $ args = $ this ->removeMatchTypeFromArguments ($ args );
12476 }
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 ();
13177
132- if ($ priceOptions ['is_filterable ' ] != 0 ) {
133- $ this ->preparePriceAggregation ($ searchCriteria );
78+ $ searchCriteria = $ this ->criteriaResolverFactory ->create (
79+ [
80+ 'searchRequestName ' => $ requestName ,
81+ 'currentPage ' => $ args ['currentPage ' ],
82+ 'size ' => $ args ['pageSize ' ],
83+ 'orders ' => null ,
84+ ]
85+ )->resolve ();
86+ foreach ($ args as $ argumentName => $ argument ) {
87+ if ($ this ->argumentApplierPool ->hasApplier ($ argumentName )) {
88+ $ argumentApplier = $ this ->argumentApplierPool ->getApplier ($ argumentName );
89+ $ argumentApplier ->applyArgument ($ searchCriteria , 'products ' , $ argumentName , $ argument );
13490 }
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 );
14391 }
144-
92+ $ this ->updateRangeFilters ($ searchCriteria );
93+ $ this ->preparePriceAggregation ($ searchCriteria , $ includeAggregation );
14594 if ($ isSearch ) {
14695 $ this ->addFilter ($ searchCriteria , 'search_term ' , $ args ['search ' ]);
14796 }
148-
14997 if (!$ searchCriteria ->getSortOrders ()) {
15098 $ this ->addDefaultSortOrder ($ searchCriteria , $ args , $ isSearch );
15199 }
152-
153100 $ this ->addEntityIdSort ($ searchCriteria );
154101 $ this ->addVisibilityFilter ($ searchCriteria , $ isSearch , !empty ($ args ['filter ' ]['category_id ' ]));
155102
156- $ searchCriteria ->setCurrentPage ($ args ['currentPage ' ]);
157- $ searchCriteria ->setPageSize ($ args ['pageSize ' ]);
158-
159103 return $ searchCriteria ;
160104 }
161105
@@ -164,7 +108,6 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte
164108 *
165109 * @param string $requestName
166110 * @param array $partialMatchFilters
167- *
168111 * @return void
169112 */
170113 private function updateMatchTypeRequestConfig (string $ requestName , array $ partialMatchFilters ): void
@@ -184,7 +127,6 @@ private function updateMatchTypeRequestConfig(string $requestName, array $partia
184127 * Check if and what type of match_type value was requested
185128 *
186129 * @param array $args
187- *
188130 * @return array
189131 */
190132 private function getPartialMatchFilters (array $ args ): array
@@ -202,7 +144,6 @@ private function getPartialMatchFilters(array $args): array
202144 * Remove the match_type to avoid search criteria containing it
203145 *
204146 * @param array $args
205- *
206147 * @return array
207148 */
208149 private function removeMatchTypeFromArguments (array $ args ): array
@@ -254,7 +195,7 @@ private function addEntityIdSort(SearchCriteriaInterface $searchCriteria): void
254195 }
255196
256197 $ sortOrderArray [] = $ this ->sortOrderBuilder
257- ->setField ('_id ' )
198+ ->setField ('entity_id ' )
258199 ->setDirection ($ sortDir )
259200 ->create ();
260201 $ searchCriteria ->setSortOrders ($ sortOrderArray );
@@ -264,10 +205,21 @@ private function addEntityIdSort(SearchCriteriaInterface $searchCriteria): void
264205 * Prepare price aggregation algorithm
265206 *
266207 * @param SearchCriteriaInterface $searchCriteria
208+ * @param bool $includeAggregation
267209 * @return void
268210 */
269- private function preparePriceAggregation (SearchCriteriaInterface $ searchCriteria ): void
211+ private function preparePriceAggregation (SearchCriteriaInterface $ searchCriteria, bool $ includeAggregation ): void
270212 {
213+ if (!$ includeAggregation ) {
214+ return ;
215+ }
216+
217+ $ attributeData = $ this ->productAttributeRepository ->get ('price ' );
218+ $ priceOptions = $ attributeData ->getData ();
219+ if ((int ) $ priceOptions ['is_filterable ' ] === 0 ) {
220+ return ;
221+ }
222+
271223 $ priceRangeCalculation = $ this ->scopeConfig ->getValue (
272224 \Magento \Catalog \Model \Layer \Filter \Dynamic \AlgorithmFactory::XML_PATH_RANGE_CALCULATION ,
273225 \Magento \Store \Model \ScopeInterface::SCOPE_STORE
@@ -319,7 +271,7 @@ private function addDefaultSortOrder(SearchCriteriaInterface $searchCriteria, ar
319271 ->setDirection (SortOrder::SORT_DESC )
320272 ->create ();
321273 } else {
322- $ categoryIdFilter = isset ( $ args ['filter ' ]['category_id ' ]) ? $ args [ ' filter ' ][ ' category_id ' ] : false ;
274+ $ categoryIdFilter = $ args ['filter ' ]['category_id ' ] ?? false ;
323275 if ($ categoryIdFilter ) {
324276 if (!is_array ($ categoryIdFilter [array_key_first ($ categoryIdFilter )])
325277 || count ($ categoryIdFilter [array_key_first ($ categoryIdFilter )]) <= 1
0 commit comments