toolshed-8.x-1.x-dev/modules/toolshed_search/src/Plugin/ToolshedSearch/Autocomplete/SearchApiAutocomplete.php
modules/toolshed_search/src/Plugin/ToolshedSearch/Autocomplete/SearchApiAutocomplete.php
<?php
namespace Drupal\toolshed_search\Plugin\ToolshedSearch\Autocomplete;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\search_api\Plugin\views\filter\SearchApiFulltext;
use Drupal\search_api\Utility\Utility;
use Drupal\search_api_autocomplete\SearchInterface;
use Drupal\search_api_autocomplete\Utility\AutocompleteHelperInterface;
use Drupal\toolshed_search\Attribute\ToolshedSearchAutocomplete;
use Drupal\toolshed_search\Plugin\Block\ToolshedSearchBlock;
use Drupal\toolshed_search\Plugin\ToolshedSearchAutocompleteInterface;
use Drupal\views\ViewExecutable;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Autocomplete plugin for Search API Autocomplete provided autocomplete.
*/
#[ToolshedSearchAutocomplete(
id: 'search_api_autocomplete',
label: new TranslatableMarkup('Search API Autocomplete'),
)]
class SearchApiAutocomplete extends PluginBase implements ToolshedSearchAutocompleteInterface, ContainerFactoryPluginInterface {
/**
* The Search API Autocomplete helper.
*
* @var \Drupal\search_api_autocomplete\Utility\AutocompleteHelperInterface|null
*/
protected ?AutocompleteHelperInterface $autocompleteHelper = NULL;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* Creates a new instance of the SearchApiAutocomplete plugin class.
*
* @param array $configuration
* The plugin configuration values.
* @param string $plugin_id
* The plugin identifier.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
$instance = new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')
);
if ($helper = $container->get('search_api_autocomplete.helper', ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
$instance->setAutocompleteHelper($helper);
}
return $instance;
}
/**
* Set the Search API Autocomplete helper.
*
* @param \Drupal\search_api_autocomplete\Utility\AutocompleteHelperInterface $autocomplete_helper
* The search_api_autocomplete autocomplete helper.
*/
public function setAutocompleteHelper(AutocompleteHelperInterface $autocomplete_helper): void {
$this->autocompleteHelper = $autocomplete_helper;
}
/**
* {@inheritdoc}
*/
public function isApplicable(ViewExecutable $view): bool {
if ($this->autocompleteHelper) {
$ac = $this->getAutocomplete($view);
return $ac && $this->isAutocompleteEnabled($view, $ac);
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function applyAutocomplete(array &$form, array &$filters, ToolshedSearchBlock $search_block): void {
if (!$this->autocompleteHelper) {
return;
}
$view = $search_block->getView();
$ac = $this->getAutocomplete($view);
if (!$ac || !$this->isAutocompleteEnabled($view, $ac)) {
return;
}
foreach ($search_block->getFilters() as $filterInfo) {
/** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $filter */
$filter = $filterInfo['filter'];
$key = $filter->options['expose']['identifier'] ?? $filter->exposedInfo()['value'];
if (!$filter instanceof SearchApiFulltext || empty($key)) {
continue;
}
// Find a reference to the filter element.
$element = NULL;
if (isset($form['filters'][$key])) {
$element = &$form['filters'][$key];
}
elseif (isset($form['filters'][$key . '_wrapper'][$key])) {
$element = &$form['filters'][$key . '_wrapper'][$key];
}
else {
continue;
}
$data = [
'display' => $view->current_display,
'arguments' => $view->args,
'filter' => $key,
];
// Some views filter plugins nest the value of the actual form element.
if (!empty($element['value'])) {
$element = &$element['value'];
$data['field'] = $filter->realField;
}
// The search autocomplete helper only deals with "textfield" types.
if ('textfield' === ($element['#type'] ?? NULL)) {
$this->autocompleteHelper->alterElement($element, $ac, $data);
}
}
}
/**
* Checks if the search API autocomplete is enabled for this view and display.
*
* @param \Drupal\views\ViewExecutable $view
* The view which executes the search functionality.
* @param \Drupal\search_api_autocomplete\SearchInterface $autocomplete
* The Search API Autcomplete configuration entity for this view.
*
* @return bool
* TRUE if the autocomplete is enabled for this view and display.
*/
protected function isAutocompleteEnabled(ViewExecutable $view, SearchInterface $autocomplete): bool {
$config = $autocomplete->getSearchPlugin()->getConfiguration();
return Utility::matches($view->current_display, $config['displays']);
}
/**
* Gets the Search API Autocomplete configurations matching a view.
*
* @param \Drupal\views\ViewExecutable $view
* View to find Search API Autocomplete configurations for.
*
* @return \Drupal\search_api_autocomplete\SearchInterface|null
* The search autocomplete config entity that matches this view.
*/
protected function getAutocomplete(ViewExecutable $view): ?SearchInterface {
$searchId = 'views:' . $view->id();
try {
/** @var \Drupal\search_api_autocomplete\Entity\SearchStorage $autocompleteStorage */
$autocompleteStorage = $this->entityTypeManager->getStorage('search_api_autocomplete_search');
return $autocompleteStorage->loadBySearchPlugin($searchId);
}
catch (InvalidPluginDefinitionException $e) {
// Search API Autocomplete likely isn't installed, and the entity type
// isn't available. Just exit out report no autocomplete is avaiable.
}
return NULL;
}
}
