View source
<?php
namespace Drupal\search_api_spellcheck\Plugin\views\area;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\search_api\Plugin\views\filter\SearchApiFulltext;
use Drupal\search_api\Query\ResultSetInterface;
use Drupal\views\Plugin\views\area\AreaPluginBase;
use Drupal\views\Views;
class SpellCheck extends AreaPluginBase {
const SPELLCHECK_CACHE_SUFFIX = ":spellcheck";
const SPELLCHECK_CACHE_BIN = "data";
private $cache;
private $filters;
private $currentQuery;
protected function defineOptions() {
$options = parent::defineOptions();
$options['search_api_spellcheck_filter_name']['default'] = 'query';
$options['search_api_spellcheck_hide_on_result']['default'] = TRUE;
return $options;
}
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['search_api_spellcheck_filter_name'] = [
'#default_value' => $this->options['search_api_spellcheck_filter_name'] ?: 'query',
'#title' => $this
->t('Enter parameter name of text search filter'),
'#type' => 'textfield',
];
$form['search_api_spellcheck_hide_on_result'] = [
'#default_value' => $this->options['search_api_spellcheck_hide_on_result'] ?? TRUE,
'#title' => $this
->t('Hide when the view has results.'),
'#type' => 'checkbox',
];
}
public function preQuery() {
$query = $this->query;
$query
->setOption('search_api_spellcheck', TRUE);
parent::preQuery();
}
protected function getCache() {
if (!$this->cache) {
if (!empty($this->live_preview)) {
$this->cache = Views::pluginManager('cache')
->createInstance('none');
}
else {
$this->cache = $this->view->display_handler
->getPlugin('cache');
}
}
return $this->cache;
}
public function postExecute(&$values) {
$result = $this->query
->getSearchApiResults();
$response = $result
->getExtraData('search_api_solr_response');
$tags = $this
->getCache()
->getCacheTags();
\Drupal::cache(self::SPELLCHECK_CACHE_BIN)
->set($this
->getCacheKey(), $response, Cache::PERMANENT, $tags);
parent::postExecute($values);
}
public function getCacheKey() {
$cache = $this
->getCache();
return $cache
->generateResultsKey() . self::SPELLCHECK_CACHE_SUFFIX;
}
public function render($empty = FALSE) {
if ($this->options['search_api_spellcheck_hide_on_result'] == FALSE || $this->options['search_api_spellcheck_hide_on_result'] && $empty) {
$cacheItem = \Drupal::cache(self::SPELLCHECK_CACHE_BIN)
->get($this
->getCacheKey());
if ($extra_data = $cacheItem->data) {
$filter_name = $this->options['search_api_spellcheck_filter_name'];
$keys = $this->view
->getExposedInput()[$filter_name];
$new_data = [];
if (!empty($extra_data['spellcheck']['suggestions'])) {
foreach ($extra_data['spellcheck']['suggestions'] as $key => $value) {
if (is_string($value)) {
$new_data[$key] = [
'error' => $value,
'suggestion' => $extra_data['spellcheck']['suggestions'][$key + 1]['suggestion'][0],
];
}
}
}
foreach ($new_data as $datum) {
$keys = str_replace($datum['error'], $datum['suggestion'], $keys);
}
$build = [
[
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $this
->t('Did you mean: '),
],
[
'#type' => 'link',
'#title' => str_replace('+', ' ', $keys),
'#url' => Url::fromRoute('<current>', [], [
'query' => [
'keys' => str_replace(' ', '+', $keys),
],
]),
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $this
->t('?'),
],
];
return $build;
}
}
return [];
}
protected function getCurrentQuery() {
if (NULL === $this->currentQuery) {
$this->currentQuery = \Drupal::request()->query
->all();
}
return $this->currentQuery;
}
protected function getFilters() {
if (NULL === $this->filters) {
$this->filters = [];
$exposed_input = $this->view
->getExposedInput();
foreach ($this->view->filter as $key => $filter) {
if ($filter instanceof SearchApiFulltext) {
if (!empty($filter->options['expose']['identifier'])) {
$key = $filter->options['expose']['identifier'];
}
$this->filters[$key] = !empty($exposed_input[$key]) ? strtolower($exposed_input[$key]) : FALSE;
}
}
}
return $this->filters;
}
private function getFilterMatch(array $suggestion) {
if ($index = array_search($suggestion[0], $this
->getFilters(), TRUE)) {
if (!empty($suggestion[1]['suggestion'][0])) {
return [
$index => $suggestion[1]['suggestion'][0],
];
}
}
}
}