Skip to content

Commit 4323d5a

Browse files
author
Oleksandr Iegorov
committed
ACP2E-132: GraphQL Feature Request - "Did you mean ..", auto-corrected term to be given in Graphql
1 parent 9c194fe commit 4323d5a

File tree

6 files changed

+165
-4
lines changed

6 files changed

+165
-4
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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;
9+
10+
use Magento\Framework\Exception\NoSuchEntityException;
11+
use Magento\Framework\Stdlib\StringUtils as StdlibString;
12+
use Magento\GraphQl\Model\Query\ContextInterface;
13+
use Magento\Search\Model\Query;
14+
use Magento\Search\Model\QueryFactory;
15+
16+
/**
17+
* Prepares search query based on search text.
18+
*/
19+
class QueryProcessor
20+
{
21+
/**
22+
* @var QueryFactory
23+
*/
24+
private $queryFactory;
25+
26+
/**
27+
* @var StdlibString
28+
*/
29+
private $string;
30+
31+
/**
32+
* @param QueryFactory $queryFactory
33+
* @param StdlibString $string
34+
*/
35+
public function __construct(
36+
QueryFactory $queryFactory,
37+
StdlibString $string
38+
) {
39+
$this->queryFactory = $queryFactory;
40+
$this->string = $string;
41+
}
42+
43+
/**
44+
* Prepare Query object based on search text
45+
*
46+
* @param ContextInterface $context
47+
* @param string $queryText
48+
* @throws NoSuchEntityException
49+
* @return Query
50+
*/
51+
public function prepare(ContextInterface $context, string $queryText) : Query
52+
{
53+
$query = $this->queryFactory->create();
54+
$maxQueryLength = (int) $query->getMaxQueryLength();
55+
if ($maxQueryLength && $this->string->strlen($queryText) > $maxQueryLength) {
56+
$queryText = $this->string->substr($queryText, 0, $maxQueryLength);
57+
}
58+
$query->setQueryText($queryText);
59+
$store = $context->getExtensionAttributes()->getStore();
60+
$query->setStoreId($store->getId());
61+
return $query;
62+
}
63+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public function resolve(
7070
$data = [
7171
'total_count' => $searchResult->getTotalCount(),
7272
'items' => $searchResult->getProductsSearchResult(),
73+
'suggestions' => $searchResult->getSuggestions(),
7374
'page_info' => [
7475
'page_size' => $searchResult->getPageSize(),
7576
'current_page' => $searchResult->getCurrentPage(),

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Magento\GraphQl\Model\Query\ContextInterface;
2020
use Magento\Search\Api\SearchInterface;
2121
use Magento\Search\Model\Search\PageSizeProvider;
22+
use Magento\Framework\Exception\NoSuchEntityException;
2223

2324
/**
2425
* Full text search for catalog using given search criteria.
@@ -60,6 +61,21 @@ class Search implements ProductQueryInterface
6061
*/
6162
private $searchCriteriaBuilder;
6263

64+
/**
65+
* @var Suggestions
66+
*/
67+
private $suggestions;
68+
69+
/**
70+
* @var StdlibString
71+
*/
72+
private $string;
73+
74+
/**
75+
* @var SuggestedQueries
76+
*/
77+
private $suggestedQueries;
78+
6379
/**
6480
* @param SearchInterface $search
6581
* @param SearchResultFactory $searchResultFactory
@@ -68,6 +84,7 @@ class Search implements ProductQueryInterface
6884
* @param ProductSearch $productsProvider
6985
* @param SearchCriteriaBuilder $searchCriteriaBuilder
7086
* @param ArgumentsProcessorInterface|null $argsSelection
87+
* @param Suggestions|null $suggestions
7188
*/
7289
public function __construct(
7390
SearchInterface $search,
@@ -76,8 +93,10 @@ public function __construct(
7693
FieldSelection $fieldSelection,
7794
ProductSearch $productsProvider,
7895
SearchCriteriaBuilder $searchCriteriaBuilder,
79-
ArgumentsProcessorInterface $argsSelection = null
80-
) {
96+
ArgumentsProcessorInterface $argsSelection = null,
97+
Suggestions $suggestions = null
98+
)
99+
{
81100
$this->search = $search;
82101
$this->searchResultFactory = $searchResultFactory;
83102
$this->pageSizeProvider = $pageSize;
@@ -86,6 +105,8 @@ public function __construct(
86105
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
87106
$this->argsSelection = $argsSelection ?: ObjectManager::getInstance()
88107
->get(ArgumentsProcessorInterface::class);
108+
$this->suggestions = $suggestions ?: ObjectManager::getInstance()
109+
->get(Suggestions::class);
89110
}
90111

91112
/**
@@ -131,14 +152,21 @@ public function getResult(
131152
$productArray[$product->getId()]['model'] = $product;
132153
}
133154

155+
$suggestions = [];
156+
$totalCount = (int) $searchResults->getTotalCount();
157+
if ($totalCount === 0 && !empty($args['search'])) {
158+
$suggestions = $this->suggestions->execute($context, $args['search']);
159+
}
160+
134161
return $this->searchResultFactory->create(
135162
[
136-
'totalCount' => $searchResults->getTotalCount(),
163+
'totalCount' => $totalCount,
137164
'productsSearchResult' => $productArray,
138165
'searchAggregation' => $itemsResults->getAggregations(),
139166
'pageSize' => $realPageSize,
140167
'currentPage' => $realCurrentPage,
141168
'totalPages' => $totalPages,
169+
'suggestions' => $suggestions,
142170
]
143171
);
144172
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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\AdvancedSearch\Model\SuggestedQueries;
11+
use Magento\GraphQl\Model\Query\ContextInterface;
12+
use Magento\CatalogGraphQl\Model\QueryProcessor;
13+
14+
/**
15+
* Search suggestions implementations for GraphQL
16+
*/
17+
class Suggestions
18+
{
19+
/**
20+
* @var QueryProcessor
21+
*/
22+
private $queryProcessor;
23+
24+
/**
25+
* @var SuggestedQueries
26+
*/
27+
private $suggestedQueries;
28+
29+
/**
30+
* @param QueryProcessor $queryProcessor
31+
* @param SuggestedQueries $suggestedQueries
32+
*/
33+
public function __construct(
34+
QueryProcessor $queryProcessor,
35+
SuggestedQueries $suggestedQueries
36+
) {
37+
$this->queryProcessor = $queryProcessor;
38+
$this->suggestedQueries = $suggestedQueries;
39+
}
40+
41+
/**
42+
* Return search suggestions for the provided query text
43+
*
44+
* @param ContextInterface $context
45+
* @param string $queryText
46+
* @return array
47+
*/
48+
public function execute(ContextInterface $context, string $queryText) : array
49+
{
50+
$result = [];
51+
$query = $this->queryProcessor->prepare($context, $queryText);
52+
$suggestionItems = $this->suggestedQueries->getItems($query);
53+
foreach ($suggestionItems as $suggestion) {
54+
$result[] = ['search' => $suggestion->getQueryText()];
55+
}
56+
return $result;
57+
}
58+
}

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/SearchResult.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,14 @@ public function getTotalPages(): int
8383
{
8484
return $this->data['totalPages'] ?? 0;
8585
}
86+
87+
/**
88+
* Retrieve an array in the format of GraphQL-readable type containing search suggestions.
89+
*
90+
* @return array
91+
*/
92+
public function getSuggestions() : array
93+
{
94+
return $this->data['suggestions'] ?? [];
95+
}
8696
}

app/code/Magento/CatalogGraphQl/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"magento/module-eav-graph-ql": "*",
1414
"magento/module-catalog-search": "*",
1515
"magento/framework": "*",
16-
"magento/module-graph-ql": "*"
16+
"magento/module-graph-ql": "*",
17+
"magento/module-advanced-search": "*"
1718
},
1819
"suggest": {
1920
"magento/module-graph-ql-cache": "*",

0 commit comments

Comments
 (0)