View source  
  <?php
namespace Drupal\search_api_autocomplete\Form;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RedirectDestinationInterface;
use Drupal\Core\Url;
use Drupal\search_api\IndexInterface;
use Drupal\search_api_autocomplete\Entity\Search;
use Drupal\search_api_autocomplete\Search\SearchPluginInterface;
use Drupal\search_api_autocomplete\Search\SearchPluginManager;
use Drupal\search_api_autocomplete\Utility\PluginHelperInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Messenger\MessengerInterface;
class IndexOverviewForm extends FormBase {
  
  protected $suggesterManager;
  
  protected $searchPluginManager;
  
  protected $pluginHelper;
  
  protected $entityTypeManager;
  
  protected $redirectDestination;
  
  protected $messenger;
  
  public function __construct(PluginManagerInterface $suggester_manager, SearchPluginManager $search_plugin_manager, PluginHelperInterface $plugin_helper, EntityTypeManagerInterface $entity_type_manager, RedirectDestinationInterface $redirect_destination, MessengerInterface $messenger) {
    $this->suggesterManager = $suggester_manager;
    $this->searchPluginManager = $search_plugin_manager;
    $this->pluginHelper = $plugin_helper;
    $this->entityTypeManager = $entity_type_manager;
    $this->redirectDestination = $redirect_destination;
    $this->messenger = $messenger;
  }
  
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('plugin.manager.search_api_autocomplete.suggester'), $container
      ->get('plugin.manager.search_api_autocomplete.search'), $container
      ->get('search_api_autocomplete.plugin_helper'), $container
      ->get('entity_type.manager'), $container
      ->get('redirect.destination'), $container
      ->get('messenger'));
  }
  
  public function getFormId() {
    return 'search_api_autocomplete_admin_overview';
  }
  
  public function buildForm(array $form, FormStateInterface $form_state, IndexInterface $search_api_index = NULL) {
    $form_state
      ->set('index', $search_api_index);
    $index_id = $search_api_index
      ->id();
    $form['#tree'] = TRUE;
    $form['#title'] = $this
      ->t('Manage autocomplete for search index %label', [
      '%label' => $search_api_index
        ->label(),
    ]);
    
    $searches_by_plugin = [];
    foreach ($this
      ->loadAutocompleteSearchByIndex($index_id) as $search) {
      $searches_by_plugin[$search
        ->getSearchPluginId()] = $search;
    }
    $used_ids = [];
    $plugins = $this->pluginHelper
      ->createSearchPluginsForIndex($index_id);
    foreach ($plugins as $plugin_id => $plugin) {
      $group_label = (string) $plugin
        ->getGroupLabel();
      if (empty($form[$group_label])) {
        $form[$group_label] = [
          '#type' => 'details',
          '#open' => TRUE,
          '#title' => $plugin
            ->getGroupLabel(),
        ];
        if ($description = $plugin
          ->getGroupDescription()) {
          $form[$group_label]['#description'] = '<p>' . $description . '</p>';
        }
        $form[$group_label]['searches']['#type'] = 'tableselect';
        $form[$group_label]['searches']['#header'] = [
          'label' => $this
            ->t('Label'),
          'operations' => $this
            ->t('Operations'),
        ];
        $form[$group_label]['searches']['#empty'] = '';
        $form[$group_label]['searches']['#js_select'] = TRUE;
      }
      if (isset($searches_by_plugin[$plugin_id])) {
        $search = $searches_by_plugin[$plugin_id];
      }
      else {
        $search = $this
          ->createSearchForPlugin($plugin, $used_ids);
        $used_ids[$search
          ->id()] = TRUE;
      }
      $id = $search
        ->id();
      $form_state
        ->set([
        'searches',
        $id,
      ], $search);
      $form[$group_label]['searches'][$id] = [
        '#type' => 'checkbox',
        '#default_value' => $search
          ->status(),
        '#parents' => [
          'searches',
          $id,
        ],
      ];
      $options =& $form[$group_label]['searches']['#options'][$id];
      $options['label'] = $search
        ->label();
      $items = [];
      if ($search
        ->status()) {
        $items[] = [
          'title' => $this
            ->t('Edit'),
          'url' => $search
            ->toUrl('edit-form'),
        ];
      }
      if (!$search
        ->isNew()) {
        $items[] = [
          'title' => $this
            ->t('Delete'),
          'url' => $search
            ->toUrl('delete-form'),
        ];
      }
      if ($items) {
        $options['operations'] = [
          'data' => [
            '#type' => 'operations',
            '#links' => $items,
          ],
        ];
      }
      else {
        $options['operations'] = '';
      }
      unset($options);
    }
    if (!Element::children($form)) {
      $form['message']['#markup'] = '<p>' . $this
        ->t('There are currently no searches known for this index. You need to create at least one search view.') . '</p>';
    }
    else {
      $form['actions'] = [
        '#type' => 'actions',
      ];
      $form['actions']['submit'] = [
        '#type' => 'submit',
        '#button_type' => 'primary',
        '#value' => $this
          ->t('Save'),
      ];
    }
    return $form;
  }
  
  protected function createSearchForPlugin(SearchPluginInterface $plugin, array $used_ids) {
    $plugin_id = $plugin
      ->getPluginId();
    $index_id = $plugin
      ->getIndexId();
    $id = $base_id = $plugin
      ->getDerivativeId() ?: $plugin_id;
    $search_storage = $this->entityTypeManager
      ->getStorage('search_api_autocomplete_search');
    $i = 0;
    while (!empty($used_ids[$id]) || $search_storage
      ->load($id)) {
      $id = $base_id . '_' . ++$i;
    }
    $search = Search::create([
      'id' => $id,
      'status' => FALSE,
      'label' => $plugin
        ->label(),
      'index_id' => $index_id,
      'search_settings' => [
        $plugin_id => [],
      ],
      'options' => [],
    ]);
    
    $suggesters = array_map(function ($suggester_info) {
      return $suggester_info['class'];
    }, $this->suggesterManager
      ->getDefinitions());
    $filter_suggesters = function ($suggester_class) use ($search) {
      return $suggester_class::supportsSearch($search);
    };
    $available_suggesters = array_filter($suggesters, $filter_suggesters);
    if ($available_suggesters) {
      reset($available_suggesters);
      $suggester_id = key($available_suggesters);
      $suggester = $this->pluginHelper
        ->createSuggesterPlugin($search, $suggester_id);
      $search
        ->setSuggesters([
        $suggester_id => $suggester,
      ]);
    }
    return $search;
  }
  
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $messages = $this
      ->t('The settings have been saved.');
    foreach ($form_state
      ->getValue('searches') as $id => $enabled) {
      
      $search = $form_state
        ->get([
        'searches',
        $id,
      ]);
      if ($search && $search
        ->status() != $enabled) {
        $change = TRUE;
        if ($search
          ->isNew()) {
          $options['query'] = $this->redirectDestination
            ->getAsArray();
          $options['fragment'] = 'module-search_api_autocomplete';
          $url = Url::fromRoute('user.admin_permissions', [], $options);
          if ($url
            ->access()) {
            $vars[':perm_url'] = $url
              ->toString();
            $messages = $this
              ->t('The settings have been saved. Please remember to set the <a href=":perm_url">permissions</a> for the newly enabled searches.', $vars);
          }
        }
        $search
          ->setStatus($enabled);
        $search
          ->save();
      }
    }
    $this->messenger
      ->addStatus(empty($change) ? $this
      ->t('No values were changed.') : $messages);
  }
  
  protected function loadAutocompleteSearchByIndex($index_id) {
    
    $searches = $this->entityTypeManager
      ->getStorage('search_api_autocomplete_search')
      ->loadByProperties([
      'index_id' => $index_id,
    ]);
    return $searches;
  }
}