Add index to AlterSettingsEvent for backward compatibility

Created on 24 March 2024, 8 months ago
Updated 24 August 2024, 3 months ago

Problem/Motivation

On 8.x-7.x there was no Event for altering the settings when creating the index. One could use PrepareIndexEvent (https://git.drupalcode.org/project/elasticsearch_connector/-/blob/8.x-7....) to alter Elasticsearch index settings based on Search API index configurations.
eg. set stemmer based on indexed content.

<?php

namespace Drupal\MY_MODULE\EventSubscriber;

use Drupal\Component\EventDispatcher\Event;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\elasticsearch_connector\ElasticSearch\Parameters\Factory\IndexFactory;
use Drupal\search_api\IndexInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class EntityTypeSubscriber.
 *
 * @package Drupal\MY_MODULE\EventSubscriber
 */
class PrepareIndexSubscriber implements EventSubscriberInterface {

  /**
   * Entity type manager.
   *
   * @var \Drupal\Core\Entity\Entity
   */
  private $entityTypeManager;

  /**
   * Constructs a new DefaultSubscriber object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   Entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * {@inheritdoc}
   *
   * @return array
   *   The event names to listen for, and the methods that should be executed.
   */
  public static function getSubscribedEvents() {
    return [
      'elasticsearch_connector.prepare_index' => 'prepareIndex',
    ];
  }

  /**
   * Called on elasticsearch_connector.prepare_index event.
   */
  public function prepareIndex(Event $event) {
    $indexConfig = $event->getIndexConfig();
    $index = $this->loadIndexFromIndexName($event->getIndexName());
    $config = $this->getDatasourceConfig($index);
    $stemmer_language = 'english';
    if (!empty($config) && isset($config['languages']['selected'])) {
      $langcode = $config['languages']['selected'][0];
      if ($langcode === 'fi') {
        $stemmer_language = 'finnish';
      }
    }
    $filter_name = $stemmer_language . '_stop';
    $filter_language = '_' . $stemmer_language . '_';

    $indexConfig["body"]["settings"]["index"] = [
      "analysis" => [
        "analyzer" => [
          "tags_analyzer" => [
            "type" => "custom",
            "filter" => [
              "lowercase",
              "stop",
              "filter_stemmer",
              $filter_name,
            ],
            "tokenizer" => "standard",
          ],
        ],
        "filter" => [
          "filter_stemmer" => [
            "type" => "stemmer",
            "language" => $stemmer_language,
          ],
          $filter_name => [
            "type" => "stop",
            "stopwords" => $filter_language,
          ],
        ],
      ],
    ];
    $event->setIndexConfig($indexConfig);
  }

  /**
   * Loads the index entity associated with this event.
   *
   * @param string $index_name
   *   The long index name as a string.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The loaded index or NULL.
   */
  private function loadIndexFromIndexName($index_name) {
    $index_storage = $this->entityTypeManager->getStorage('search_api_index');
    /** @var \Drupal\search_api\Entity\Index[] $search_api_indexes */
    $search_api_indexes = $index_storage->loadMultiple();

    foreach ($search_api_indexes as $search_api_index) {
      $elasticsearch_connector_index_name = IndexFactory::getIndexName($search_api_index);
      if ($index_name == $elasticsearch_connector_index_name) {
        return $search_api_index;
      }
    }

    return NULL;
  }

  /**
   * Returns the datasource configuration for the given index.
   *
   * @param \Drupal\search_api\IndexInterface $index
   *   The Search API index entity.
   *
   * @return array
   *   An array representing the datasource configuration.
   *
   * @throws \Drupal\search_api\SearchApiException
   */
  protected function getDatasourceConfig(IndexInterface $index) {
    $config = [];
    if ($index->isValidDatasource('entity:node')) {
      $config = $index->getDatasource('entity:node')->getConfiguration();
    }
    return $config;
  }

}

Proposed resolution

Add Drupal\search_api\IndexInterface $index to AlterSettingsEvent constructor argument.

Remaining tasks

User interface changes

None.

API changes

The \Drupal\elasticsearch_connector\Event\AlterSettingsEvent now stores a reference to the Elasticsearch index (i.e.: an instance of \Drupal\search_api\IndexInterface), which you can retrieve with \Drupal\elasticsearch_connector\Event\AlterSettingsEvent->getIndex().

Data model changes

None.

📌 Task
Status

Fixed

Version

8.0

Component

Code

Created by

🇫🇮Finland sokru

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Production build 0.71.5 2024