Skip to content
Snippets Groups Projects

Support multiple spelling suggestions and retain original search terms

Merged Andrew Clement requested to merge issue/search_api_fusion-3303165:1.0.x into 1.0.x
Files
2
@@ -2,9 +2,9 @@
@@ -2,9 +2,9 @@
namespace Drupal\search_api_fusion\Plugin\views\area;
namespace Drupal\search_api_fusion\Plugin\views\area;
use Drupal\Core\Url;
use Drupal\Core\Link;
use Drupal\Core\Link;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Path\CurrentPathStack;
 
use Drupal\Core\Url;
use Drupal\views\Plugin\views\area\AreaPluginBase;
use Drupal\views\Plugin\views\area\AreaPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -82,45 +82,53 @@ class FusionSpellcheck extends AreaPluginBase {
@@ -82,45 +82,53 @@ class FusionSpellcheck extends AreaPluginBase {
return [];
return [];
}
}
// If Fusion provided spellcheck suggestions: order those by frequency.
$suggestions = $response['spellcheck']['suggestions'];
$suggestions = $response['spellcheck']['suggestions'];
$word = NULL;
$best_suggestions = [];
foreach ($suggestions as $word => $data) {
foreach ($suggestions as $delta => &$data) {
if (isset($data['suggestion'])) {
// Ensure the suggestion array is defined. This skips string elements in
usort($suggestions[$word]['suggestion'],
// the array that solely contain a search term.
function ($suggestion1, $suggestion2): int {
if (isset($data['suggestion']) && !empty($data['suggestion'])) {
return $suggestion1['freq'] <=> $suggestion2['freq'];
// Order Fusion provided spellcheck suggestions by frequency.
});
usort($data['suggestion'],
 
function ($suggestion1, $suggestion2): int {
 
return $suggestion1['freq'] <=> $suggestion2['freq'];
 
});
 
// The original search term is in the array element previous to the
 
// suggestions.
 
$search_term = $suggestions[$delta - 1];
 
// Extract suggested word with the highest frequency (last array
 
// element). Use the original search term as the array key.
 
$best_suggestions[$search_term] = $data['suggestion'][array_key_last($data['suggestion'])]['word'];
}
}
}
}
if (empty($suggestions[$word]['suggestion'])
if (empty($best_suggestions)) {
|| !is_array($suggestions[$word]['suggestion'])) {
return [];
return [];
}
}
// Extract suggestion with highest frequency.
$link = $this->getSuggestionLink($best_suggestions);
end($suggestions[$word]['suggestion']);
if (is_null($link)) {
$best_suggestion = current($suggestions[$word]['suggestion']);
return [];
}
// Return hyperlink "Did you mean: <best spellcheck suggestion> ?".
// Return hyperlink "Did you mean: <best spellcheck suggestion> ?".
return [
return [
'#theme' => 'search_api_fusion_spellcheck',
'#theme' => 'search_api_fusion_spellcheck',
'#label' => $this->t('Did you mean:'),
'#label' => $this->t('Did you mean:'),
'#link' => $this->getSuggestionLink($best_suggestion['word']),
'#link' => $link,
];
];
}
}
/**
/**
* Gets the suggestion link.
* Gets the suggestion link.
*
*
* @param string $suggestion
* @param array $suggestions
* The suggested search query.
* Array of suggested spellcheck words keyed by the original search terms.
*
*
* @return \Drupal\Core\Link
* @return Link|NULL
* The suggestion link.
* The suggestion link or NULL if the query is not set or the suggested
 
* text matches the original search terms.
*/
*/
protected function getSuggestionLink($suggestion) {
protected function getSuggestionLink(array $suggestions) {
if ($this->view->hasUrl()) {
if ($this->view->hasUrl()) {
$path = '/' . $this->view->getPath();
$path = '/' . $this->view->getPath();
}
}
@@ -129,15 +137,38 @@ class FusionSpellcheck extends AreaPluginBase {
@@ -129,15 +137,38 @@ class FusionSpellcheck extends AreaPluginBase {
}
}
$currentQuery = $this->getCurrentQuery();
$currentQuery = $this->getCurrentQuery();
unset($currentQuery['q']);
unset($currentQuery['q']);
 
if (!isset($currentQuery['query'])) {
 
return NULL;
 
}
 
 
// Search and replace the original search terms with the returned suggested
 
// words. This way the original search terms without a spelling suggestion
 
// are preserved.
 
// Use the original search term(s) as a default.
 
$suggested_text = $currentQuery['query'];
 
foreach ($suggestions as $original_term => $suggested_term) {
 
// Replace only full words and not part of a word.
 
$suggested_text = preg_replace(
 
'/\b' . $original_term . '\b/u',
 
$suggested_term,
 
$suggested_text
 
);
 
}
 
 
// Handle the rare possibility of the original search term(s) matching the
 
// suggested text.
 
if ($suggested_text == $currentQuery['query']) {
 
return NULL;
 
}
 
$url = Url::fromUserInput($path, [
$url = Url::fromUserInput($path, [
'query' => [
'query' => [
'query' => $suggestion,
'query' => $suggested_text,
] + $currentQuery,
] + $currentQuery,
]);
]);
return Link::fromTextAndUrl($suggestion, $url);
return Link::fromTextAndUrl($suggested_text, $url);
}
}
/**
/**
@@ -146,7 +177,7 @@ class FusionSpellcheck extends AreaPluginBase {
@@ -146,7 +177,7 @@ class FusionSpellcheck extends AreaPluginBase {
* @return array
* @return array
* Key value of parameters.
* Key value of parameters.
*/
*/
protected function getCurrentQuery() {
public function getCurrentQuery(): array {
if (NULL === $this->currentQuery) {
if (NULL === $this->currentQuery) {
$this->currentQuery = $this->view->getRequest()->query->all();
$this->currentQuery = $this->view->getRequest()->query->all();
}
}
Loading