[ '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'); }