v1/web/modules/contrib/search_api_autocomplete/search_api_autocomplete.module

248 lines
7.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
/**
* @file
* Adds autocomplete capabilities for Search API searches.
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\search_api\Plugin\views\query\SearchApiQuery;
use Drupal\search_api_autocomplete\Search\SearchPluginDeriverBase;
use Drupal\search_api_page\SearchApiPageInterface;
use Drupal\views\ViewEntityInterface;
/**
* Implements hook_theme().
*/
function search_api_autocomplete_theme() {
$themes['search_api_autocomplete_suggestion'] = [
'variables' => [
'keys' => NULL,
'url' => NULL,
'label' => NULL,
'note' => NULL,
'results_count' => NULL,
'suggestion_prefix' => '',
'suggestion_suffix' => '',
'user_input' => '',
],
];
return $themes;
}
/**
* Implements hook_entity_operation().
*/
function search_api_autocomplete_entity_operation(EntityInterface $entity) {
if ($entity->getEntityTypeId() != 'search_api_index') {
return [];
}
$operations = [];
$operations['autocomplete'] = [
'title' => t('Autocomplete'),
'weight' => 30,
'url' => Url::fromRoute('search_api_autocomplete.admin_overview', ['search_api_index' => $entity->id()]),
];
return $operations;
}
/**
* Implements hook_hook_info().
*
* Allows other modules to place all their hook implementations for this module
* into a "MODULE.search_api_autocomplete.inc" file.
*/
function search_api_autocomplete_hook_info() {
$hooks = [
'search_api_autocomplete_suggestions_alter',
'search_api_autocomplete_suggester_info_alter',
'search_api_autocomplete_search_info_alter',
'search_api_autocomplete_views_fulltext_fields_alter',
];
$info = [
'group' => 'search_api_autocomplete',
];
return array_fill_keys($hooks, $info);
}
/**
* Implements hook_form_FORM_ID_alter() for "views_exposed_form".
*
* Adds autocompletion to input fields for fulltext keywords on views with
* exposed filters.
*
* @see \Drupal\views\Form\ViewsExposedForm
* @see \Drupal\search_api_autocomplete\Plugin\search_api_autocomplete\search\Views
*/
function search_api_autocomplete_form_views_exposed_form_alter(array &$form, FormStateInterface $form_state) {
/** @var \Drupal\views\ViewExecutable $view */
$view = $form_state->get('view');
if (substr($view->storage->get('base_table'), 0, 17) != 'search_api_index_') {
return;
}
$plugin_id = 'views:' . $view->id();
$cache_tag = "search_api_autocomplete_search_list:$plugin_id";
if (!isset($form['#cache']['tags'])
|| !in_array($cache_tag, $form['#cache']['tags'])) {
$form['#cache']['tags'][] = $cache_tag;
}
/** @var \Drupal\search_api_autocomplete\Entity\SearchStorage $search_storage */
$search_storage = \Drupal::entityTypeManager()
->getStorage('search_api_autocomplete_search');
$search = $search_storage->loadBySearchPlugin($plugin_id);
if (!$search || !$search->status()) {
return;
}
$config = $search->getSearchPlugin()->getConfiguration();
$selected = in_array($view->current_display, $config['displays']['selected']);
// @todo Replace with \Drupal\search_api\Utility\Utility::matches() once
// we can use it (Search API 1.8 dependency).
if ($selected == $config['displays']['default']) {
return;
}
$fields = $search->getIndex()->getFulltextFields();
if (!$fields) {
return;
}
// Add the "Search: Fulltext search" filter as another text field.
$fields[] = 'search_api_fulltext';
\Drupal::moduleHandler()->alter('search_api_autocomplete_views_fulltext_fields', $fields, $search, $view);
$base_data = [
'display' => $view->current_display,
'arguments' => $view->args,
];
foreach ($view->filter as $filter_name => $filter) {
if (!in_array($filter->realField, $fields)
|| empty($filter->options['expose']['identifier'])) {
continue;
}
$key = $filter->options['expose']['identifier'];
if (isset($form[$key])) {
$element = &$form[$key];
}
elseif (isset($form[$key . '_wrapper'][$key])) {
$element = &$form[$key . '_wrapper'][$key];
}
else {
continue;
}
$data = $base_data;
// The Views filter for individual fulltext fields uses a nested "value"
// field for the real input, due to Views internals.
if (!empty($element['value'])) {
$element = &$element['value'];
// In this case, we also need to manually pass the fulltext fields, so
// they will be applied properly.
$data['field'] = $filter->realField;
}
if (isset($element['#type']) && $element['#type'] === 'textfield') {
$data['filter'] = $key;
\Drupal::getContainer()
->get('search_api_autocomplete.helper')
->alterElement($element, $search, $data);
}
unset($element);
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for "search_api_page_block_form".
*
* Adds autocompletion to the keywords field on search pages, if enabled by the
* user.
*
* @see \Drupal\search_api_page\Form\SearchApiPageBlockForm
* @see \Drupal\search_api_autocomplete\Plugin\search_api_autocomplete\search\Page
*/
function search_api_autocomplete_form_search_api_page_block_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
$page_id = substr($form_id, strlen('search_api_page_block_form_'));
/** @var \Drupal\search_api_autocomplete\Entity\SearchStorage $search_storage */
$search_storage = \Drupal::entityTypeManager()
->getStorage('search_api_autocomplete_search');
$plugin_id = 'page:' . $page_id;
$search = $search_storage->loadBySearchPlugin($plugin_id);
$cache_tag = "search_api_autocomplete_search_list:$plugin_id";
if (!isset($form['#cache']['tags'])
|| !in_array($cache_tag, $form['#cache']['tags'])) {
$form['#cache']['tags'][] = $cache_tag;
}
if ($search && $search->status()) {
\Drupal::getContainer()
->get('search_api_autocomplete.helper')
->alterElement($form['keys'], $search);
}
}
/**
* Implements hook_ENTITY_TYPE_insert() for type "view".
*
* Clear the search plugin definitions cache when new search views are created.
* Could use better support from the Plugin API see #2633878.
*/
function search_api_autocomplete_view_insert(ViewEntityInterface $view) {
if (SearchApiQuery::getIndexFromTable($view->get('base_table'))) {
\Drupal::getContainer()
->get('plugin.manager.search_api_autocomplete.search')
->clearCachedDefinitions();
SearchPluginDeriverBase::resetStaticDerivativeCaches('views');
}
}
/**
* Implements hook_ENTITY_TYPE_delete() for type "view".
*
* Clear the search plugin definitions cache when search views are deleted.
* Could use better support from the Plugin API see #2633878.
*/
function search_api_autocomplete_view_delete(ViewEntityInterface $view) {
if (SearchApiQuery::getIndexFromTable($view->get('base_table'))) {
\Drupal::getContainer()
->get('plugin.manager.search_api_autocomplete.search')
->clearCachedDefinitions();
SearchPluginDeriverBase::resetStaticDerivativeCaches('views');
}
}
/**
* Implements hook_ENTITY_TYPE_insert() for type "search_api_page".
*
* Clear the search plugin definitions cache when search pages are created.
* Could use better support from the Plugin API see #2633878.
*/
function search_api_autocomplete_search_api_page_insert(SearchApiPageInterface $page) {
\Drupal::getContainer()
->get('plugin.manager.search_api_autocomplete.search')
->clearCachedDefinitions();
SearchPluginDeriverBase::resetStaticDerivativeCaches('page');
}
/**
* Implements hook_ENTITY_TYPE_delete() for type "search_api_page".
*
* Clear the search plugin definitions cache when search pages are deleted.
* Could use better support from the Plugin API see #2633878.
*/
function search_api_autocomplete_search_api_page_delete(SearchApiPageInterface $page) {
\Drupal::getContainer()
->get('plugin.manager.search_api_autocomplete.search')
->clearCachedDefinitions();
SearchPluginDeriverBase::resetStaticDerivativeCaches('page');
}