You are here

class Index in Search API 8

Defines the search index configuration entity.

Plugin annotation


@ConfigEntityType(
  id = "search_api_index",
  label = @Translation("Search index"),
  label_collection = @Translation("Search indexes"),
  label_singular = @Translation("search index"),
  label_plural = @Translation("search indexes"),
  label_count = @PluralTranslation(
    singular = "@count search index",
    plural = "@count search indexes",
  ),
  handlers = {
    "storage" = "Drupal\search_api\Entity\SearchApiConfigEntityStorage",
    "list_builder" = "Drupal\search_api\IndexListBuilder",
    "form" = {
      "default" = "Drupal\search_api\Form\IndexForm",
      "edit" = "Drupal\search_api\Form\IndexForm",
      "fields" = "Drupal\search_api\Form\IndexFieldsForm",
      "add_fields" = "Drupal\search_api\Form\IndexAddFieldsForm",
      "field_config" = "Drupal\search_api\Form\FieldConfigurationForm",
      "break_lock" = "Drupal\search_api\Form\IndexBreakLockForm",
      "processors" = "Drupal\search_api\Form\IndexProcessorsForm",
      "delete" = "Drupal\search_api\Form\IndexDeleteConfirmForm",
      "disable" = "Drupal\search_api\Form\IndexDisableConfirmForm",
      "reindex" = "Drupal\search_api\Form\IndexReindexConfirmForm",
      "clear" = "Drupal\search_api\Form\IndexClearConfirmForm",
      "rebuild_tracker" = "Drupal\search_api\Form\IndexRebuildTrackerConfirmForm",
    },
  },
  admin_permission = "administer search_api",
  config_prefix = "index",
  entity_keys = {
    "id" = "id",
    "label" = "name",
    "uuid" = "uuid",
    "status" = "status",
  },
  config_export = {
    "id",
    "name",
    "description",
    "read_only",
    "field_settings",
    "datasource_settings",
    "processor_settings",
    "tracker_settings",
    "options",
    "server",
  },
  links = {
    "canonical" = "/admin/config/search/search-api/index/{search_api_index}",
    "add-form" = "/admin/config/search/search-api/add-index",
    "edit-form" = "/admin/config/search/search-api/index/{search_api_index}/edit",
    "fields" = "/admin/config/search/search-api/index/{search_api_index}/fields",
    "add-fields" = "/admin/config/search/search-api/index/{search_api_index}/fields/add/nojs",
    "add-fields-ajax" = "/admin/config/search/search-api/index/{search_api_index}/fields/add/ajax",
    "break-lock-form" = "/admin/config/search/search-api/index/{search_api_index}/fields/break-lock",
    "processors" = "/admin/config/search/search-api/index/{search_api_index}/processors",
    "delete-form" = "/admin/config/search/search-api/index/{search_api_index}/delete",
    "disable" = "/admin/config/search/search-api/index/{search_api_index}/disable",
    "enable" = "/admin/config/search/search-api/index/{search_api_index}/enable",
  }
)

Hierarchy

Expanded class hierarchy of Index

53 files declare their use of Index
AggregatedFieldsTest.php in tests/src/Unit/Processor/AggregatedFieldsTest.php
BackendTest.php in modules/search_api_db/tests/src/Kernel/BackendTest.php
BackendTestBase.php in tests/src/Kernel/BackendTestBase.php
BasicTrackerTest.php in tests/src/Kernel/BasicTrackerTest.php
BundlelessEntityTest.php in tests/src/Kernel/Datasource/BundlelessEntityTest.php

... See full list

1 string reference to 'Index'
IndexListBuilder::buildRow in src/IndexListBuilder.php
Builds a row for an entity in the entity listing.

File

src/Entity/Index.php, line 94

Namespace

Drupal\search_api\Entity
View source
class Index extends ConfigEntityBase implements IndexInterface {
  use InstallingTrait;
  use LoggerTrait;

  /**
   * The ID of the index.
   *
   * @var string
   */
  protected $id;

  /**
   * A name to be displayed for the index.
   *
   * @var string
   */
  protected $name;

  /**
   * A string describing the index.
   *
   * @var string
   */
  protected $description;

  /**
   * A flag indicating whether to write to this index.
   *
   * @var bool
   */
  protected $read_only = FALSE;

  /**
   * An array of field settings.
   *
   * @var array
   */
  protected $field_settings = [];

  /**
   * An array of field instances.
   *
   * In the ::preSave method we're saving the contents of these back into the
   * $field_settings array. When adding, removing or changing configuration we
   * should always use these.
   *
   * @var \Drupal\search_api\Item\FieldInterface[]|null
   */
  protected $fieldInstances;

  /**
   * An array of options configuring this index.
   *
   * @var array
   *
   * @see getOptions()
   */
  protected $options = [];

  /**
   * The settings of the datasources selected for this index.
   *
   * The array has the following structure:
   *
   * @code
   * [
   *   'DATASOURCE_ID' => [
   *     // Settings …
   *   ],
   *   …
   * ]
   * @endcode
   *
   * @var array
   */
  protected $datasource_settings = [];

  /**
   * The instantiated datasource plugins.
   *
   * In the ::preSave method we're saving the contents of these back into the
   * $datasource_settings array. When adding, removing or changing configuration
   * we should therefore always manipulate this property instead of the stored
   * one.
   *
   * @var \Drupal\search_api\Datasource\DatasourceInterface[]|null
   *
   * @see getDatasources()
   */
  protected $datasourceInstances;

  /**
   * The tracker settings.
   *
   * The array has the following structure:
   *
   * @code
   * [
   *   'TRACKER_ID' => [
   *     // Settings …
   *   ],
   * ]
   * @endcode
   *
   * There is always just a single entry in the array.
   *
   * @var array
   */
  protected $tracker_settings = NULL;

  /**
   * The tracker plugin instance.
   *
   * In the ::preSave method we're saving the contents of these back into the
   * $tracker_settings array. When adding, removing or changing configuration
   * we should therefore always manipulate this property instead of the stored
   * one.
   *
   * @var \Drupal\search_api\Tracker\TrackerInterface|null
   *
   * @see getTrackerInstance()
   */
  protected $trackerInstance;

  /**
   * The ID of the server on which data should be indexed.
   *
   * @var string|null
   */
  protected $server;

  /**
   * The server entity belonging to this index.
   *
   * @var \Drupal\search_api\ServerInterface
   *
   * @see getServerInstance()
   */
  protected $serverInstance;

  /**
   * The array of processor settings.
   *
   * The array has the following structure:
   *
   * @code
   * [
   *   'PROCESSOR_ID' => [
   *     'weights' => [],
   *     // Other settings …
   *   ],
   *   …
   * ]
   * @endcode
   *
   * @var array
   */
  protected $processor_settings = [];

  /**
   * Instances of the processor plugins.
   *
   * In the ::preSave method we're saving the contents of these back into the
   * $tracker_settings array. When adding, removing or changing configuration
   * we should therefore always manipulate this property instead of the stored
   * one.
   *
   * @var \Drupal\search_api\Processor\ProcessorInterface[]|null
   */
  protected $processorInstances;

  /**
   * Static cache of retrieved property definitions, grouped by datasource.
   *
   * @var \Drupal\Core\TypedData\DataDefinitionInterface[][]
   *
   * @see \Drupal\search_api\Entity\Index::getPropertyDefinitions()
   */
  protected $properties = [];

  /**
   * The number of currently active "batch tracking" modes.
   *
   * @var int
   */
  protected $batchTracking = 0;

  /**
   * {@inheritdoc}
   */
  public function id() {
    return $this->id;
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription() {
    return $this->description;
  }

  /**
   * {@inheritdoc}
   */
  public function isReadOnly() {
    return $this->read_only;
  }

  /**
   * {@inheritdoc}
   */
  public function getOption($name, $default = NULL) {
    return $this->options[$name] ?? $default;
  }

  /**
   * {@inheritdoc}
   */
  public function getOptions() {
    return $this->options;
  }

  /**
   * {@inheritdoc}
   */
  public function setOption($name, $option) {
    $this->options[$name] = $option;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setOptions(array $options) {
    $this->options = $options;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getDatasources() {
    if ($this->datasourceInstances === NULL) {
      $this->datasourceInstances = \Drupal::getContainer()
        ->get('search_api.plugin_helper')
        ->createDatasourcePlugins($this, array_keys($this->datasource_settings));
    }
    return $this->datasourceInstances;
  }

  /**
   * {@inheritdoc}
   */
  public function getDatasourceIds() {
    return array_keys($this
      ->getDatasources());
  }

  /**
   * {@inheritdoc}
   */
  public function isValidDatasource($datasource_id) {
    $datasources = $this
      ->getDatasources();
    return !empty($datasources[$datasource_id]);
  }

  /**
   * {@inheritdoc}
   */
  public function getDatasource($datasource_id) {
    $datasources = $this
      ->getDatasources();
    if (empty($datasources[$datasource_id])) {
      $index_label = $this
        ->label();
      throw new SearchApiException("The datasource with ID '{$datasource_id}' could not be retrieved for index '{$index_label}'.");
    }
    return $datasources[$datasource_id];
  }

  /**
   * {@inheritdoc}
   */
  public function addDatasource(DatasourceInterface $datasource) {

    // Make sure the datasourceInstances are loaded before trying to add a plugin
    // to them.
    if ($this->datasourceInstances === NULL) {
      $this
        ->getDatasources();
    }
    $this->datasourceInstances[$datasource
      ->getPluginId()] = $datasource;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function removeDatasource($datasource_id) {

    // Make sure the datasourceInstances are loaded before trying to remove a
    // plugin from them.
    if ($this->datasourceInstances === NULL) {
      $this
        ->getDatasources();
    }
    unset($this->datasourceInstances[$datasource_id]);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setDatasources(array $datasources = NULL) {
    $this->datasourceInstances = $datasources;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getEntityTypes($return_bool = FALSE) {
    $types = [];
    foreach ($this
      ->getDatasources() as $datasource_id => $datasource) {
      if ($type = $datasource
        ->getEntityTypeId()) {
        $types[$datasource_id] = $type;
      }
    }
    return $types;
  }

  /**
   * {@inheritdoc}
   */
  public function hasValidTracker() {
    return (bool) \Drupal::getContainer()
      ->get('plugin.manager.search_api.tracker')
      ->getDefinition($this
      ->getTrackerId(), FALSE);
  }

  /**
   * {@inheritdoc}
   */
  public function getTrackerId() {
    if ($this->trackerInstance) {
      return $this->trackerInstance
        ->getPluginId();
    }
    if (empty($this->tracker_settings)) {
      return \Drupal::config('search_api.settings')
        ->get('default_tracker');
    }
    reset($this->tracker_settings);
    return key($this->tracker_settings);
  }

  /**
   * {@inheritdoc}
   */
  public function getTrackerInstance() {
    if (!$this->trackerInstance) {
      $tracker_id = $this
        ->getTrackerId();
      $configuration = [];
      if (!empty($this->tracker_settings[$tracker_id])) {
        $configuration = $this->tracker_settings[$tracker_id];
      }
      $this->trackerInstance = \Drupal::getContainer()
        ->get('search_api.plugin_helper')
        ->createTrackerPlugin($this, $tracker_id, $configuration);
    }
    return $this->trackerInstance;
  }

  /**
   * {@inheritdoc}
   */
  public function setTracker(TrackerInterface $tracker) {
    $this->trackerInstance = $tracker;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function hasValidServer() {
    return $this->serverInstance || $this->server !== NULL && Server::load($this->server);
  }

  /**
   * {@inheritdoc}
   */
  public function isServerEnabled() {
    return $this
      ->hasValidServer() && $this
      ->getServerInstance()
      ->status();
  }

  /**
   * {@inheritdoc}
   */
  public function getServerId() {
    return $this->server;
  }

  /**
   * {@inheritdoc}
   */
  public function getServerInstance() {
    if (!$this->serverInstance && $this->server) {
      $this->serverInstance = Server::load($this->server);
      if (!$this->serverInstance) {
        $index_label = $this
          ->label();
        throw new SearchApiException("The server with ID '{$this->server}' could not be retrieved for index '{$index_label}'.");
      }
    }
    return $this->serverInstance;
  }

  /**
   * {@inheritdoc}
   */
  public function setServer(ServerInterface $server = NULL) {
    $this->serverInstance = $server;
    $this->server = $server ? $server
      ->id() : NULL;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getProcessors() {
    if ($this->processorInstances !== NULL) {
      return $this->processorInstances;
    }

    // Filter the processors to only include those that are enabled (or locked).
    // We should only reach this point in the code once, at the first call after
    // the index is loaded.
    $this->processorInstances = [];
    $processors = \Drupal::getContainer()
      ->get('search_api.plugin_helper')
      ->createProcessorPlugins($this);
    foreach ($processors as $processor_id => $processor) {
      if (isset($this->processor_settings[$processor_id]) || $processor
        ->isLocked()) {
        $this->processorInstances[$processor_id] = $processor;
      }
    }
    return $this->processorInstances;
  }

  /**
   * {@inheritdoc}
   */
  public function getProcessorsByStage($stage, array $overrides = []) {

    // Get a list of all processors which support this stage, along with their
    // weights.
    $processors = $this
      ->getProcessors();
    $processor_weights = [];
    foreach ($processors as $name => $processor) {
      if ($processor
        ->supportsStage($stage)) {
        $processor_weights[$name] = $processor
          ->getWeight($stage);
      }
    }

    // Apply any overrides that were passed by the caller.
    $plugin_helper = \Drupal::getContainer()
      ->get('search_api.plugin_helper');
    foreach ($overrides as $name => $config) {
      $processor = $plugin_helper
        ->createProcessorPlugin($this, $name, $config);
      if ($processor
        ->supportsStage($stage)) {
        $processors[$name] = $processor;
        $processor_weights[$name] = $processor
          ->getWeight($stage);
      }
      else {

        // In rare cases, the override might change whether or not the processor
        // supports the given stage. So, to make sure, unset the weight in case
        // it was set before.
        unset($processor_weights[$name]);
      }
    }

    // Sort requested processors by weight.
    asort($processor_weights);
    $return_processors = [];
    foreach ($processor_weights as $name => $weight) {
      $return_processors[$name] = $processors[$name];
    }
    return $return_processors;
  }

  /**
   * {@inheritdoc}
   */
  public function isValidProcessor($processor_id) {
    $processors = $this
      ->getProcessors();
    return !empty($processors[$processor_id]);
  }

  /**
   * {@inheritdoc}
   */
  public function getProcessor($processor_id) {
    $processors = $this
      ->getProcessors();
    if (empty($processors[$processor_id])) {
      $index_label = $this
        ->label();
      throw new SearchApiException("The processor with ID '{$processor_id}' could not be retrieved for index '{$index_label}'.");
    }
    return $processors[$processor_id];
  }

  /**
   * {@inheritdoc}
   */
  public function addProcessor(ProcessorInterface $processor) {

    // Make sure the processorInstances are loaded before trying to add a plugin
    // to them.
    if ($this->processorInstances === NULL) {
      $this
        ->getProcessors();
    }
    $this->processorInstances[$processor
      ->getPluginId()] = $processor;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function removeProcessor($processor_id) {

    // Make sure the processorInstances are loaded before trying to remove a
    // plugin from them.
    if ($this->processorInstances === NULL) {
      $this
        ->getProcessors();
    }
    unset($this->processorInstances[$processor_id]);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setProcessors(array $processors) {
    $this->processorInstances = $processors;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function alterIndexedItems(array &$items) {
    foreach ($this
      ->getProcessorsByStage(ProcessorInterface::STAGE_ALTER_ITEMS) as $processor) {
      $processor
        ->alterIndexedItems($items);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function preprocessIndexItems(array $items) {
    foreach ($this
      ->getProcessorsByStage(ProcessorInterface::STAGE_PREPROCESS_INDEX) as $processor) {
      $processor
        ->preprocessIndexItems($items);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function preprocessSearchQuery(QueryInterface $query) {
    foreach ($this
      ->getProcessorsByStage(ProcessorInterface::STAGE_PREPROCESS_QUERY) as $processor) {
      $processor
        ->preprocessSearchQuery($query);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function postprocessSearchResults(ResultSetInterface $results) {
    foreach ($this
      ->getProcessorsByStage(ProcessorInterface::STAGE_POSTPROCESS_QUERY) as $processor) {
      $processor
        ->postprocessSearchResults($results);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function addField(FieldInterface $field) {
    $field_id = $field
      ->getFieldIdentifier();
    $reserved = \Drupal::getContainer()
      ->get('search_api.fields_helper')
      ->isFieldIdReserved($field_id);
    if ($reserved) {
      throw new SearchApiException("'{$field_id}' is a reserved value and cannot be used as the machine name of a normal field.");
    }

    // This will automatically call getFields(), thus initializing
    // $this->fieldInstances, if that hasn't been done yet.
    $old_field = $this
      ->getField($field_id);
    if ($old_field && $old_field != $field) {
      throw new SearchApiException("Cannot add field with machine name '{$field_id}': machine name is already taken.");
    }
    $this->fieldInstances[$field_id] = $field;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function renameField($old_field_id, $new_field_id) {
    if (!isset($this
      ->getFields()[$old_field_id])) {
      throw new SearchApiException("Could not rename field with machine name '{$old_field_id}': no such field.");
    }
    $reserved = \Drupal::getContainer()
      ->get('search_api.fields_helper')
      ->isFieldIdReserved($new_field_id);
    if ($reserved) {
      throw new SearchApiException("'{$new_field_id}' is a reserved value and cannot be used as the machine name of a normal field.");
    }
    if (isset($this
      ->getFields()[$new_field_id])) {
      throw new SearchApiException("'{$new_field_id}' already exists and can't be used as a new field id.");
    }
    $this->fieldInstances[$new_field_id] = $this->fieldInstances[$old_field_id];
    unset($this->fieldInstances[$old_field_id]);
    $this->fieldInstances[$new_field_id]
      ->setFieldIdentifier($new_field_id);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function removeField($field_id) {
    $field = $this
      ->getField($field_id);
    if (!$field) {
      return $this;
    }
    if ($field
      ->isIndexedLocked()) {
      throw new SearchApiException("Cannot remove field with machine name '{$field_id}': field is locked.");
    }
    unset($this->fieldInstances[$field_id]);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setFields(array $fields) {
    $this->fieldInstances = $fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getFields($include_server_defined = FALSE) {
    if (!isset($this->fieldInstances)) {
      $this->fieldInstances = [];
      foreach ($this->field_settings as $key => $field_info) {
        $this->fieldInstances[$key] = \Drupal::getContainer()
          ->get('search_api.fields_helper')
          ->createField($this, $key, $field_info);
      }
    }
    $fields = $this->fieldInstances;
    if ($include_server_defined && $this
      ->hasValidServer()) {
      $fields += $this
        ->getServerInstance()
        ->getBackendDefinedFields($this);
    }
    return $fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getField($field_id) {
    $fields = $this
      ->getFields();
    return $fields[$field_id] ?? NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function getFieldsByDatasource($datasource_id) {
    $datasource_fields = [];
    foreach ($this
      ->getFields() as $field_id => $field) {
      if ($field
        ->getDatasourceId() === $datasource_id) {
        $datasource_fields[$field_id] = $field;
      }
    }
    return $datasource_fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getFulltextFields() {
    $fulltext_fields = [];
    foreach ($this
      ->getFields() as $key => $field) {
      if (\Drupal::getContainer()
        ->get('search_api.data_type_helper')
        ->isTextType($field
        ->getType())) {
        $fulltext_fields[] = $key;
      }
    }
    return $fulltext_fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getFieldRenames() {
    $renames = [];
    foreach ($this
      ->getFields() as $field_id => $field) {
      if ($field
        ->getOriginalFieldIdentifier() != $field_id) {
        $renames[$field
          ->getOriginalFieldIdentifier()] = $field_id;
      }
    }
    return $renames;
  }

  /**
   * {@inheritdoc}
   */
  public function discardFieldChanges() {
    $this->fieldInstances = NULL;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getPropertyDefinitions($datasource_id) {
    if (!isset($this->properties[$datasource_id])) {
      if (isset($datasource_id)) {
        $datasource = $this
          ->getDatasource($datasource_id);
        $properties = $datasource
          ->getPropertyDefinitions();
      }
      else {
        $datasource = NULL;
        $properties = [];
      }
      foreach ($this
        ->getProcessorsByStage(ProcessorInterface::STAGE_ADD_PROPERTIES) as $processor) {
        $properties += $processor
          ->getPropertyDefinitions($datasource);
      }
      $this->properties[$datasource_id] = $properties;
    }
    return $this->properties[$datasource_id];
  }

  /**
   * {@inheritdoc}
   */
  public function loadItem($item_id) {
    $items = $this
      ->loadItemsMultiple([
      $item_id,
    ]);
    return $items ? reset($items) : NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function loadItemsMultiple(array $item_ids) {

    // Group the requested items by datasource. This will also later be used to
    // determine whether all items were loaded successfully.
    $items_by_datasource = [];
    foreach ($item_ids as $item_id) {
      list($datasource_id, $raw_id) = Utility::splitCombinedId($item_id);
      $items_by_datasource[$datasource_id][$raw_id] = $item_id;
    }

    // Load the items from the datasources and keep track of which were
    // successfully retrieved.
    $items = [];
    foreach ($items_by_datasource as $datasource_id => $raw_ids) {
      try {
        $datasource = $this
          ->getDatasource($datasource_id);
        $datasource_items = $datasource
          ->loadMultiple(array_keys($raw_ids));
        foreach ($datasource_items as $raw_id => $item) {
          $id = $raw_ids[$raw_id];
          $items[$id] = $item;

          // Remember that we successfully loaded this item.
          unset($items_by_datasource[$datasource_id][$raw_id]);
        }
      } catch (SearchApiException $e) {
        $this
          ->logException($e);

        // If the complete datasource could not be loaded, don't report all its
        // individual requested items as missing.
        unset($items_by_datasource[$datasource_id]);
      }
    }

    // Check whether there are requested items that couldn't be loaded.
    $items_by_datasource = array_filter($items_by_datasource);
    if ($items_by_datasource) {

      // Extract the second-level values of the two-dimensional array (that is,
      // the combined item IDs) and log a warning reporting their absence.
      $missing_ids = array_reduce(array_map('array_values', $items_by_datasource), 'array_merge', []);
      $args['%index'] = $this
        ->label();
      $args['@items'] = '"' . implode('", "', $missing_ids) . '"';
      $this
        ->getLogger()
        ->warning('Could not load the following items on index %index: @items.', $args);

      // Also remove those items from tracking so we don't keep trying to load
      // them.
      foreach ($items_by_datasource as $datasource_id => $raw_ids) {
        $this
          ->trackItemsDeleted($datasource_id, array_keys($raw_ids));
      }
    }

    // Return the loaded items.
    return $items;
  }

  /**
   * {@inheritdoc}
   */
  public function indexItems($limit = '-1', $datasource_id = NULL) {
    if ($this
      ->hasValidTracker() && !$this
      ->isReadOnly()) {
      $tracker = $this
        ->getTrackerInstance();
      $next_set = $tracker
        ->getRemainingItems($limit, $datasource_id);
      if (!$next_set) {
        return 0;
      }
      $items = $this
        ->loadItemsMultiple($next_set);
      if (!$items) {
        return 0;
      }
      try {
        return count($this
          ->indexSpecificItems($items));
      } catch (SearchApiException $e) {
        $variables['%index'] = $this
          ->label();
        $this
          ->logException($e, '%type while trying to index items on index %index: @message in %function (line %line of %file)', $variables);
      }
    }
    return 0;
  }

  /**
   * {@inheritdoc}
   */
  public function indexSpecificItems(array $search_objects) {
    if (!$search_objects || $this->read_only) {
      return [];
    }
    if (!$this->status) {
      $index_label = $this
        ->label();
      throw new SearchApiException("Couldn't index values on index '{$index_label}' (index is disabled)");
    }

    /** @var \Drupal\search_api\Item\ItemInterface[] $items */
    $items = [];
    foreach ($search_objects as $item_id => $object) {
      $items[$item_id] = \Drupal::getContainer()
        ->get('search_api.fields_helper')
        ->createItemFromObject($this, $object, $item_id);
    }

    // Remember the items that were initially passed, to be able to determine
    // the items rejected by alter hooks and processors afterwards.
    $rejected_ids = array_keys($items);
    $rejected_ids = array_combine($rejected_ids, $rejected_ids);

    // Preprocess the indexed items.
    $this
      ->alterIndexedItems($items);
    $description = 'This hook is deprecated in search_api:8.x-1.14 and is removed from search_api:2.0.0. Please use the "search_api.indexing_items" event instead. See https://www.drupal.org/node/3059866';
    \Drupal::moduleHandler()
      ->alterDeprecated($description, 'search_api_index_items', $this, $items);
    $event = new IndexingItemsEvent($this, $items);
    \Drupal::getContainer()
      ->get('event_dispatcher')
      ->dispatch(SearchApiEvents::INDEXING_ITEMS, $event);
    $items = $event
      ->getItems();
    foreach ($items as $item) {

      // This will cache the extracted fields so processors, etc., can retrieve
      // them directly.
      $item
        ->getFields();
    }
    $this
      ->preprocessIndexItems($items);

    // Remove all items still in $items from $rejected_ids. Thus, only the
    // rejected items' IDs are still contained in $ret, to later be returned
    // along with the successfully indexed ones.
    foreach ($items as $item_id => $item) {
      unset($rejected_ids[$item_id]);
    }

    // Items that are rejected should also be deleted from the server.
    if ($rejected_ids) {
      $this
        ->getServerInstance()
        ->deleteItems($this, $rejected_ids);
    }
    $indexed_ids = [];
    if ($items) {
      $indexed_ids = $this
        ->getServerInstance()
        ->indexItems($this, $items);
    }

    // Return the IDs of all items that were either successfully indexed or
    // rejected before being handed to the server.
    $processed_ids = array_merge(array_values($rejected_ids), array_values($indexed_ids));
    if ($processed_ids) {
      if ($this
        ->hasValidTracker()) {
        $this
          ->getTrackerInstance()
          ->trackItemsIndexed($processed_ids);
      }

      // Since we've indexed items now, triggering reindexing would have some
      // effect again. Therefore, we reset the flag.
      $this
        ->setHasReindexed(FALSE);
      $description = 'This hook is deprecated in search_api:8.x-1.14 and is removed from search_api:2.0.0. Please use the "search_api.items_indexed" event instead. See https://www.drupal.org/node/3059866';
      \Drupal::moduleHandler()
        ->invokeAllDeprecated($description, 'search_api_items_indexed', [
        $this,
        $processed_ids,
      ]);
      $dispatcher = \Drupal::getContainer()
        ->get('event_dispatcher');
      $dispatcher
        ->dispatch(SearchApiEvents::ITEMS_INDEXED, new ItemsIndexedEvent($this, $processed_ids));

      // Clear search api list caches.
      Cache::invalidateTags([
        'search_api_list:' . $this->id,
      ]);
    }

    // When indexing via Drush, multiple iterations of a batch will happen in
    // the same PHP process, so the static cache will quickly fill up. To
    // prevent this, clear it after each batch of items gets indexed.
    if (function_exists('drush_backend_batch_process') && batch_get()) {
      \Drupal::getContainer()
        ->get('entity.memory_cache')
        ->deleteAll();
    }
    return $processed_ids;
  }

  /**
   * {@inheritdoc}
   */
  public function isBatchTracking() {
    return (bool) $this->batchTracking;
  }

  /**
   * {@inheritdoc}
   */
  public function startBatchTracking() {
    $this->batchTracking++;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function stopBatchTracking() {
    if (!$this->batchTracking) {
      throw new SearchApiException('Trying to leave "batch tracking" mode on index "' . $this
        ->label() . '" which was not entered first.');
    }
    $this->batchTracking--;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function trackItemsInserted($datasource_id, array $ids) {
    $this
      ->trackItemsInsertedOrUpdated($datasource_id, $ids, __FUNCTION__);
  }

  /**
   * {@inheritdoc}
   */
  public function trackItemsUpdated($datasource_id, array $ids) {
    $this
      ->trackItemsInsertedOrUpdated($datasource_id, $ids, __FUNCTION__);
  }

  /**
   * Tracks insertion or updating of items.
   *
   * Used as a helper method in trackItemsInserted() and trackItemsUpdated() to
   * avoid code duplication.
   *
   * @param string $datasource_id
   *   The ID of the datasource to which the items belong.
   * @param array $ids
   *   An array of datasource-specific item IDs.
   * @param string $tracker_method
   *   The method to call on the tracker. Must be either "trackItemsInserted" or
   *   "trackItemsUpdated".
   */
  protected function trackItemsInsertedOrUpdated($datasource_id, array $ids, $tracker_method) {
    if ($this
      ->hasValidTracker() && $this
      ->status()) {
      $item_ids = [];
      foreach ($ids as $id) {
        $item_ids[] = Utility::createCombinedId($datasource_id, $id);
      }
      $this
        ->getTrackerInstance()
        ->{$tracker_method}($item_ids);
      if (!$this
        ->isReadOnly() && $this
        ->getOption('index_directly') && !$this->batchTracking) {
        \Drupal::getContainer()
          ->get('search_api.post_request_indexing')
          ->registerIndexingOperation($this
          ->id(), $item_ids);
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function trackItemsDeleted($datasource_id, array $ids) {
    if (!$this
      ->status()) {
      return;
    }
    $item_ids = [];
    foreach ($ids as $id) {
      $item_ids[] = Utility::createCombinedId($datasource_id, $id);
    }
    if ($this
      ->hasValidTracker()) {
      $this
        ->getTrackerInstance()
        ->trackItemsDeleted($item_ids);
    }
    if (!$this
      ->isReadOnly() && $this
      ->hasValidServer()) {
      $this
        ->getServerInstance()
        ->deleteItems($this, $item_ids);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function reindex() {
    if ($this
      ->status() && !$this
      ->isReindexing()) {
      $this
        ->setHasReindexed();
      $this
        ->getTrackerInstance()
        ->trackAllItemsUpdated();
      $description = 'This hook is deprecated in search_api:8.x-1.14 and is removed from search_api:2.0.0. Please use the "search_api.reindex_scheduled" event instead. See https://www.drupal.org/node/3059866';
      \Drupal::moduleHandler()
        ->invokeAllDeprecated($description, 'search_api_index_reindex', [
        $this,
        FALSE,
      ]);

      /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher */
      $dispatcher = \Drupal::getContainer()
        ->get('event_dispatcher');
      $dispatcher
        ->dispatch(SearchApiEvents::REINDEX_SCHEDULED, new ReindexScheduledEvent($this, FALSE));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function clear() {
    if (!$this
      ->status()) {
      return;
    }

    // Only invoke the hook if we actually did something.
    $invoke_hook = FALSE;
    if (!$this
      ->isReindexing()) {
      $invoke_hook = TRUE;
      $this
        ->setHasReindexed();
      $this
        ->getTrackerInstance()
        ->trackAllItemsUpdated();
    }
    if (!$this
      ->isReadOnly()) {
      $invoke_hook = TRUE;
      $this
        ->getServerInstance()
        ->deleteAllIndexItems($this);
    }
    if ($invoke_hook) {
      $description = 'This hook is deprecated in search_api:8.x-1.14 and is removed from search_api:2.0.0. Please use the "search_api.reindex_scheduled" event instead. See https://www.drupal.org/node/3059866';
      \Drupal::moduleHandler()
        ->invokeAllDeprecated($description, 'search_api_index_reindex', [
        $this,
        !$this
          ->isReadOnly(),
      ]);

      /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher */
      $dispatcher = \Drupal::getContainer()
        ->get('event_dispatcher');
      $dispatcher
        ->dispatch(SearchApiEvents::REINDEX_SCHEDULED, new ReindexScheduledEvent($this, !$this
        ->isReadOnly()));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function rebuildTracker() {
    if (!$this
      ->status()) {
      return;
    }
    $index_task_manager = \Drupal::getContainer()
      ->get('search_api.index_task_manager');
    $index_task_manager
      ->stopTracking($this);
    $index_task_manager
      ->startTracking($this);
    $this
      ->setHasReindexed();
    $description = 'This hook is deprecated in search_api:8.x-1.14 and is removed from search_api:2.0.0. Please use the "search_api.reindex_scheduled" event instead. See https://www.drupal.org/node/3059866';
    \Drupal::moduleHandler()
      ->invokeAllDeprecated($description, 'search_api_index_reindex', [
      $this,
      FALSE,
    ]);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher */
    $dispatcher = \Drupal::getContainer()
      ->get('event_dispatcher');
    $dispatcher
      ->dispatch(SearchApiEvents::REINDEX_SCHEDULED, new ReindexScheduledEvent($this, FALSE));
    $index_task_manager
      ->addItemsBatch($this);
  }

  /**
   * {@inheritdoc}
   */
  public function isReindexing() {
    $key = "search_api.index.{$this->id()}.has_reindexed";
    return \Drupal::state()
      ->get($key, FALSE);
  }

  /**
   * Sets whether this index has all items marked for re-indexing.
   *
   * @param bool $has_reindexed
   *   (optional) TRUE if the index has all items marked for re-indexing, FALSE
   *   otherwise.
   *
   * @return $this
   */
  protected function setHasReindexed($has_reindexed = TRUE) {
    if ($this
      ->isReindexing() !== $has_reindexed) {
      $key = "search_api.index.{$this->id()}.has_reindexed";
      \Drupal::state()
        ->set($key, $has_reindexed);
    }
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function query(array $options = []) {
    if (!$this
      ->status()) {
      throw new SearchApiException('Cannot search on a disabled index.');
    }
    return \Drupal::getContainer()
      ->get('search_api.query_helper')
      ->createQuery($this, $options);
  }

  /**
   * {@inheritdoc}
   */
  public function postCreate(EntityStorageInterface $storage) {
    parent::postCreate($storage);

    // Merge in default options.
    $config = \Drupal::config('search_api.settings');
    $this->options += [
      'cron_limit' => $config
        ->get('default_cron_limit'),
      'index_directly' => TRUE,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function preSave(EntityStorageInterface $storage) {

    // If we are in the process of syncing, or in the process of installing
    // configuration from an extension, we shouldn't change any entity
    // properties (or other configuration).
    if ($this
      ->isSyncing() || $this
      ->isInstallingFromExtension()) {
      parent::preSave($storage);
      return;
    }

    // Retrieve active config overrides for this index.
    $overrides = Utility::getConfigOverrides($this);

    // Prevent enabling of indexes when the server is disabled. Take into
    // account that both the index's "status" and "server" properties might be
    // overridden.
    if ($this
      ->status() && !isset($overrides['status'])) {

      // NULL would be a valid override, so we can't use isset() here.
      if (!array_key_exists('server', $overrides)) {
        if (!$this
          ->isServerEnabled()) {
          $this
            ->disable();
        }
      }
      else {
        $server_id = $overrides['server'];
        $server = $server_id !== NULL ? Server::load($server_id) : NULL;
        if (!$server || !$server
          ->status()) {
          $this
            ->disable();
        }
      }
    }

    // Merge in default options.
    $config = \Drupal::config('search_api.settings');
    $this->options += [
      'cron_limit' => $config
        ->get('default_cron_limit'),
      'index_directly' => TRUE,
    ];

    // Reset the static cache for getPropertyDefinitions() to make sure we don't
    // remove any fields just because of caching problems.
    $this->properties = [];
    foreach ($this
      ->getFields() as $field_id => $field) {

      // Remove all "locked" and "hidden" flags from all fields of the index. If
      // they are still valid, they should be re-added by the processors.
      $field
        ->setIndexedLocked(FALSE);
      $field
        ->setTypeLocked(FALSE);
      $field
        ->setHidden(FALSE);

      // Also check whether the underlying property actually (still) exists.
      $datasource_id = $field
        ->getDatasourceId();
      $property = NULL;
      if ($datasource_id === NULL || $this
        ->isValidDatasource($datasource_id)) {
        $properties = $this
          ->getPropertyDefinitions($datasource_id);
        $property = \Drupal::getContainer()
          ->get('search_api.fields_helper')
          ->retrieveNestedProperty($properties, $field
          ->getPropertyPath());
      }
      if (!$property) {
        $this
          ->removeField($field_id);
      }
    }

    // Check whether all enabled processors actually still support this index.
    // (Since we can't remove processors which are present in overrides anyways,
    // we don't need to take overrides into account here.)
    foreach ($this
      ->getProcessors() as $processor_id => $processor) {
      if (!$processor
        ->supportsIndex($this)) {
        $this
          ->removeProcessor($processor_id);
      }
    }

    // Call the preIndexSave() method of all applicable processors.
    $processor_overrides = !empty($overrides['processor_settings']) ? $overrides['processor_settings'] : [];
    foreach ($this
      ->getProcessorsByStage(ProcessorInterface::STAGE_PRE_INDEX_SAVE, $processor_overrides) as $processor) {
      $processor
        ->preIndexSave();
    }

    // Write the field and plugin settings to the persistent *_settings
    // properties.
    $this
      ->writeChangesToSettings();

    // Since we change dependency-relevant data in this method, we can only call
    // the parent method at the end (or we'd need to re-calculate the
    // dependencies).
    parent::preSave($storage);
  }

  /**
   * Prepares for changes to this index to be persisted.
   *
   * To this end, the settings for all loaded field and plugin objects are
   * written back to the corresponding *_settings properties.
   *
   * @return $this
   */
  protected function writeChangesToSettings() {

    // Calculate field dependencies and save field settings containing them.
    $fields = $this
      ->getFields();
    $field_dependencies = $this
      ->getFieldDependencies();
    $field_dependencies += array_fill_keys(array_keys($fields), []);
    $this->field_settings = [];
    foreach ($fields as $field_id => $field) {
      $field
        ->setDependencies($field_dependencies[$field_id]);
      $this->field_settings[$field_id] = $field
        ->getSettings();
    }

    // Write the enabled processors to the settings property.
    $processors = $this
      ->getProcessors();
    $this->processor_settings = [];
    foreach ($processors as $processor_id => $processor) {
      $this->processor_settings[$processor_id] = $processor
        ->getConfiguration();
    }

    // Write the tracker configuration to the settings property.
    $tracker = $this
      ->getTrackerInstance();
    $tracker_id = $tracker
      ->getPluginId();
    $this->tracker_settings = [
      $tracker_id => $tracker
        ->getConfiguration(),
    ];

    // Write the enabled datasources to the settings array.
    $this->datasource_settings = [];
    foreach ($this
      ->getDatasources() as $plugin_id => $datasource) {
      $this->datasource_settings[$plugin_id] = $datasource
        ->getConfiguration();
    }
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    parent::postSave($storage, $update);

    // New indexes don't have any items indexed.
    if (!$update) {
      $this
        ->setHasReindexed();
    }
    try {

      // Fake an original for inserts to make code cleaner.

      /** @var \Drupal\search_api\IndexInterface $original */
      $original = $update ? $this->original : static::create([
        'status' => FALSE,
      ]);
      $index_task_manager = \Drupal::getContainer()
        ->get('search_api.index_task_manager');
      if ($this
        ->status() && $original
        ->status()) {

        // React on possible changes that would require re-indexing, etc.
        $this
          ->reactToServerSwitch($original);
        $this
          ->reactToDatasourceSwitch($original);
        $this
          ->reactToTrackerSwitch($original);
        $this
          ->reactToProcessorChanges($original);
      }
      elseif (!$this
        ->status() && $original
        ->status()) {
        if ($this
          ->hasValidTracker()) {
          $index_task_manager
            ->stopTracking($original);
        }
        if ($original
          ->isServerEnabled()) {
          $original
            ->getServerInstance()
            ->removeIndex($original);
        }
      }
      elseif ($this
        ->status() && !$original
        ->status()) {
        $this
          ->getServerInstance()
          ->addIndex($this);
        if ($this
          ->hasValidTracker()) {
          $index_task_manager
            ->startTracking($this);
        }
      }
      if (!$index_task_manager
        ->isTrackingComplete($this)) {

        // Give tests and site admins the possibility to disable the use of a
        // batch for tracking items. Also, do not use a batch if running in the
        // CLI.
        $use_batch = \Drupal::state()
          ->get('search_api_use_tracking_batch', TRUE);
        if (!$use_batch || Utility::isRunningInCli()) {
          $index_task_manager
            ->addItemsAll($this);
        }
        elseif (!defined('MAINTENANCE_MODE') || !in_array(MAINTENANCE_MODE, [
          'install',
          'update',
        ])) {
          $index_task_manager
            ->addItemsBatch($this);
        }
      }
      if (\Drupal::moduleHandler()
        ->moduleExists('views')) {
        Views::viewsData()
          ->clear();

        // Remove this line when https://www.drupal.org/node/2370365 gets fixed.
        Cache::invalidateTags([
          'extension:views',
        ]);
        \Drupal::cache('discovery')
          ->delete('views:wizard');
      }
      Cache::invalidateTags($this
        ->getCacheTags());
      $this->properties = [];
    } catch (SearchApiException $e) {
      $this
        ->logException($e);
    }
  }

  /**
   * Checks whether the index switched server and reacts accordingly.
   *
   * Used as a helper method in postSave(). Should only be called when the index
   * was enabled before the change and remained so.
   *
   * @param \Drupal\search_api\IndexInterface $original
   *   The previous version of the index.
   */
  protected function reactToServerSwitch(IndexInterface $original) {

    // Asserts that the index was enabled before saving and will still be
    // enabled afterwards. Otherwise, this method should not be called.
    assert($this
      ->status() && $original
      ->status(), '::reactToServerSwitch should only be called when the index is enabled');
    if ($this
      ->getServerId() != $original
      ->getServerId()) {
      if ($original
        ->hasValidServer()) {
        $original
          ->getServerInstance()
          ->removeIndex($this);
      }
      if ($this
        ->hasValidServer()) {
        $this
          ->getServerInstance()
          ->addIndex($this);
      }

      // When the server changes we also need to trigger a reindex.
      $this
        ->reindex();
    }
    elseif ($this
      ->hasValidServer()) {

      // Tell the server the index configuration got updated.
      $this
        ->getServerInstance()
        ->updateIndex($this);
    }
  }

  /**
   * Checks whether the index's datasources changed and reacts accordingly.
   *
   * Used as a helper method in postSave(). Should only be called when the index
   * was enabled before the change and remained so.
   *
   * @param \Drupal\search_api\IndexInterface $original
   *   The previous version of the index.
   */
  protected function reactToDatasourceSwitch(IndexInterface $original) {

    // Asserts that the index was enabled before saving and will still be
    // enabled afterwards. Otherwise, this method should not be called.
    assert($this
      ->status() && $original
      ->status(), '::reactToDatasourceSwitch should only be called when the index is enabled');
    $new_datasource_ids = $this
      ->getDatasourceIds();
    $original_datasource_ids = $original
      ->getDatasourceIds();
    if ($new_datasource_ids != $original_datasource_ids) {
      $added = array_diff($new_datasource_ids, $original_datasource_ids);
      $removed = array_diff($original_datasource_ids, $new_datasource_ids);
      $index_task_manager = \Drupal::getContainer()
        ->get('search_api.index_task_manager');
      $index_task_manager
        ->stopTracking($this, $removed);
      if ($this
        ->hasValidServer()) {

        /** @var \Drupal\search_api\ServerInterface $server */
        $server = $this
          ->getServerInstance();
        foreach ($removed as $datasource_id) {
          $server
            ->deleteAllIndexItems($this, $datasource_id);
        }
      }
      $index_task_manager
        ->startTracking($this, $added);
    }
  }

  /**
   * Checks whether the index switched tracker plugin and reacts accordingly.
   *
   * Used as a helper method in postSave(). Should only be called when the index
   * was enabled before the change and remained so.
   *
   * @param \Drupal\search_api\IndexInterface $original
   *   The previous version of the index.
   */
  protected function reactToTrackerSwitch(IndexInterface $original) {

    // Asserts that the index was enabled before saving and will still be
    // enabled afterwards. Otherwise, this method should not be called.
    assert($this
      ->status() && $original
      ->status(), '::reactToTrackerSwitch should only be called when the index is enabled');
    if ($this
      ->getTrackerId() != $original
      ->getTrackerId()) {
      $index_task_manager = \Drupal::getContainer()
        ->get('search_api.index_task_manager');
      if ($original
        ->hasValidTracker()) {
        $index_task_manager
          ->stopTracking($original);
      }
      if ($this
        ->hasValidTracker()) {
        $index_task_manager
          ->startTracking($this);
      }
    }
  }

  /**
   * Reacts to changes in processor configuration.
   *
   * @param \Drupal\search_api\IndexInterface $original
   *   The previous version of the index.
   */
  protected function reactToProcessorChanges(IndexInterface $original) {
    $old_processors = $original
      ->getProcessors();
    $new_processors = $this
      ->getProcessors();
    $requires_reindex = FALSE;

    // Loop over all new settings and check if the processors were already set
    // in the original entity.
    foreach ($new_processors as $key => $processor) {

      // The processor is new, because it wasn't configured in the original
      // entity.
      if (!isset($old_processors[$key])) {
        if ($processor
          ->requiresReindexing(NULL, $processor
          ->getConfiguration())) {
          $requires_reindex = TRUE;
          break;
        }
      }
    }
    if (!$requires_reindex) {

      // Loop over all original settings and check if one of them has been
      // removed or changed.
      foreach ($old_processors as $key => $old_processor) {
        $new_processor = $new_processors[$key] ?? NULL;
        $old_config = $old_processor
          ->getConfiguration();
        $new_config = $new_processor ? $new_processor
          ->getConfiguration() : NULL;
        if (!$new_processor || $old_config != $new_config) {
          if ($old_processor
            ->requiresReindexing($old_config, $new_config)) {
            $requires_reindex = TRUE;
            break;
          }
        }
      }
    }
    if ($requires_reindex) {
      $this
        ->reindex();
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function preDelete(EntityStorageInterface $storage, array $entities) {
    parent::preDelete($storage, $entities);
    $index_task_manager = \Drupal::getContainer()
      ->get('search_api.index_task_manager');

    /** @var \Drupal\search_api\IndexInterface[] $entities */
    foreach ($entities as $index) {
      if ($index
        ->status()) {
        $index_task_manager
          ->stopTracking($index);
        if ($index
          ->hasValidServer()) {
          $index
            ->getServerInstance()
            ->removeIndex($index);
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function postDelete(EntityStorageInterface $storage, array $entities) {
    parent::postDelete($storage, $entities);
    if (\Drupal::moduleHandler()
      ->moduleExists('views')) {
      Views::viewsData()
        ->clear();

      // Remove this line when https://www.drupal.org/node/2370365 gets fixed.
      Cache::invalidateTags([
        'extension:views',
      ]);
      \Drupal::cache('discovery')
        ->delete('views:wizard');
    }

    /** @var \Drupal\Core\TempStore\SharedTempStore $temp_store */
    $temp_store = \Drupal::service('tempstore.shared')
      ->get('search_api_index');
    foreach ($entities as $entity) {
      try {
        $temp_store
          ->delete($entity
          ->id());
      } catch (TempStoreException $e) {

        // Can't really be helped, I guess. But is also very unlikely to happen.
        // Ignore it.
      }
    }
  }

  // @todo Override static load() etc. methods? Measure performance difference.

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    $dependencies = $this
      ->getDependencyData();

    // Keep only "enforced" dependencies, then add those computed by
    // getDependencyData().
    $this->dependencies = array_intersect_key($this->dependencies, [
      'enforced' => TRUE,
    ]);
    $this->dependencies += array_map('array_keys', $dependencies);
    return $this;
  }

  /**
   * Retrieves data about this index's dependencies.
   *
   * The return value is structured as follows:
   *
   * @code
   * [
   *   'config' => [
   *     'CONFIG_DEPENDENCY_KEY' => [
   *       'always' => [
   *         'processors' => [
   *           'PROCESSOR_ID' => $processor,
   *         ],
   *         'datasources' => [
   *           'DATASOURCE_ID_1' => $datasource_1,
   *           'DATASOURCE_ID_2' => $datasource_2,
   *         ],
   *       ],
   *       'optional' => [
   *         'index' => [
   *           'INDEX_ID' => $index,
   *         ],
   *         'tracker' => [
   *           'TRACKER_ID' => $tracker,
   *         ],
   *       ],
   *     ],
   *   ],
   * ]
   * @endcode
   *
   * Enforced dependencies are not included in this method's return value.
   *
   * @return object[][][][][]
   *   An associative array containing the index's dependencies. The array is
   *   first keyed by the config dependency type ("module", "config", etc.) and
   *   then by the names of the config dependencies of that type which the index
   *   has. The values are associative arrays with up to two keys, "always" and
   *   "optional", specifying whether the dependency is a hard one by the plugin
   *   (or index) in question or potentially depending on the configuration. The
   *   values on this level are arrays with keys "index", "tracker",
   *   "datasources" and/or "processors" and values arrays of IDs mapped to
   *   their entities/plugins.
   */
  protected function getDependencyData() {
    $dependency_data = [];

    // Since calculateDependencies() will work directly on the $dependencies
    // property, we first save its original state and then restore it
    // afterwards.
    $original_dependencies = $this->dependencies;
    parent::calculateDependencies();
    unset($this->dependencies['enforced']);
    foreach ($this->dependencies as $dependency_type => $list) {
      foreach ($list as $name) {
        $dependency_data[$dependency_type][$name]['always']['index'][$this->id] = $this;
      }
    }
    $this->dependencies = $original_dependencies;

    // Include the field dependencies.
    $type_dependencies = [];
    foreach ($this
      ->getFields() as $field_id => $field) {
      foreach ($field
        ->getDependencies() as $dependency_type => $names) {
        foreach ($names as $name) {
          $dependency_data[$dependency_type][$name]['always']['fields'][$field_id] = $field;
        }
      }

      // Also take dependencies of the field's data type plugin into account.
      // (Since data type plugins cannot have configuration, this will always be
      // the same for a certain type, so we only have to compute this once per
      // type.)
      $type = $field
        ->getType();
      if (!isset($type_dependencies[$type])) {
        $type_dependencies[$type] = [];
        $data_type = $field
          ->getDataTypePlugin();
        if ($data_type && !$data_type
          ->isDefault()) {
          $definition = $data_type
            ->getPluginDefinition();
          $type_dependencies[$type]['module'][] = $definition['provider'];

          // Plugins can declare additional dependencies in their definition.
          if (!empty($definition['config_dependencies'])) {
            $type_dependencies[$type] = NestedArray::mergeDeep($type_dependencies[$type], $definition['config_dependencies']);
          }

          // If a plugin is dependent, calculate its dependencies.
          if ($data_type instanceof DependentPluginInterface) {
            $type_dependencies[$type] = NestedArray::mergeDeep($type_dependencies[$type], $data_type
              ->calculateDependencies());
          }
        }
      }
      foreach ($type_dependencies[$type] as $dependency_type => $list) {
        foreach ($list as $name) {
          $dependency_data[$dependency_type][$name]['optional']['fields'][$field_id] = $field;
        }
      }
    }

    // The server needs special treatment, since it is a dependency of the index
    // itself, and not one of its plugins.
    if ($this
      ->hasValidServer()) {
      $name = $this
        ->getServerInstance()
        ->getConfigDependencyName();
      $dependency_data['config'][$name]['optional']['index'][$this->id] = $this;
    }

    // All other plugins can be treated uniformly.
    $plugins = $this
      ->getAllPlugins();
    foreach ($plugins as $plugin_type => $type_plugins) {
      foreach ($type_plugins as $plugin_id => $plugin) {

        // Largely copied from
        // \Drupal\Core\Plugin\PluginDependencyTrait::calculatePluginDependencies().
        $definition = $plugin
          ->getPluginDefinition();

        // First, always depend on the module providing the plugin.
        $dependency_data['module'][$definition['provider']]['always'][$plugin_type][$plugin_id] = $plugin;

        // Plugins can declare additional dependencies in their definition.
        if (isset($definition['config_dependencies'])) {
          foreach ($definition['config_dependencies'] as $dependency_type => $list) {
            foreach ($list as $name) {
              $dependency_data[$dependency_type][$name]['always'][$plugin_type][$plugin_id] = $plugin;
            }
          }
        }

        // Finally, add the dynamically-calculated dependencies of the plugin.
        foreach ($plugin
          ->calculateDependencies() as $dependency_type => $list) {
          foreach ($list as $name) {
            $dependency_data[$dependency_type][$name]['optional'][$plugin_type][$plugin_id] = $plugin;
          }
        }
      }
    }
    return $dependency_data;
  }

  /**
   * Retrieves information about the dependencies of the indexed fields.
   *
   * @return string[][][]
   *   An associative array containing the dependencies of the indexed fields.
   *   The array is keyed by field ID and dependency type, the values are arrays
   *   with dependency names.
   */
  protected function getFieldDependencies() {
    $field_dependencies = [];
    foreach ($this
      ->getDatasources() as $datasource_id => $datasource) {
      $fields = [];
      foreach ($this
        ->getFieldsByDatasource($datasource_id) as $field_id => $field) {
        $fields[$field_id] = $field
          ->getPropertyPath();
      }
      $field_dependencies += $datasource
        ->getFieldDependencies($fields);
    }
    return $field_dependencies;
  }

  /**
   * {@inheritdoc}
   */
  public function onDependencyRemoval(array $dependencies) {
    $changed = parent::onDependencyRemoval($dependencies);
    $all_plugins = $this
      ->getAllPlugins();
    $dependency_data = $this
      ->getDependencyData();

    // Make sure our dependency data has the exact same keys as $dependencies,
    // to simplify the subsequent code.
    $dependencies = array_filter($dependencies);
    $dependency_data = array_intersect_key($dependency_data, $dependencies);
    $dependency_data += array_fill_keys(array_keys($dependencies), []);
    $call_on_removal = [];
    foreach ($dependencies as $dependency_type => $dependency_objects) {

      // Annoyingly, modules and theme dependencies come not keyed by dependency
      // name here, while entities do. Flip the array for modules and themes to
      // make the code simpler.
      if (in_array($dependency_type, [
        'module',
        'theme',
      ])) {
        $dependency_objects = array_flip($dependency_objects);
      }
      $dependency_data[$dependency_type] = array_intersect_key($dependency_data[$dependency_type], $dependency_objects);
      foreach ($dependency_data[$dependency_type] as $name => $dependency_sources) {

        // We first remove all the "hard" dependencies.
        if (!empty($dependency_sources['always'])) {
          foreach ($dependency_sources['always'] as $plugin_type => $plugins) {

            // We can hardly remove the index itself.
            if ($plugin_type == 'index') {
              continue;
            }

            // This will definitely lead to a change.
            $changed = TRUE;
            if ($plugin_type == 'fields') {

              // Remove a field from the index that is being removed from the
              // system.

              /** @var \Drupal\search_api\Item\FieldInterface $field */
              foreach ($plugins as $field_id => $field) {

                // In case the field is locked, unlock it before removing.
                if ($field
                  ->isIndexedLocked()) {
                  $field
                    ->setIndexedLocked(FALSE);
                }
                $this
                  ->removeField($field_id);
              }
            }
            else {

              // For all other types, just remove the plugin from our list.
              $all_plugins[$plugin_type] = array_diff_key($all_plugins[$plugin_type], $plugins);
            }
          }
        }

        // Then, collect all the optional ones.
        if (!empty($dependency_sources['optional'])) {

          // However this plays out, it will lead to a change.
          $changed = TRUE;
          foreach ($dependency_sources['optional'] as $plugin_type => $plugins) {

            // Deal with the index right away, since that dependency can only be
            // the server.
            if ($plugin_type == 'index') {
              $this
                ->setServer(NULL);
              continue;
            }

            // Fields can only have optional dependencies caused by their data
            // type plugin. Reset to the fallback type.
            if ($plugin_type == 'fields') {
              foreach ($plugins as $field) {
                $field
                  ->setType($field
                  ->getDataTypePlugin()
                  ->getFallbackType());
              }
              continue;
            }

            // Only include those plugins that have not already been removed.
            $plugins = array_intersect_key($plugins, $all_plugins[$plugin_type]);
            foreach ($plugins as $plugin_id => $plugin) {
              $call_on_removal[$plugin_type][$plugin_id][$dependency_type][$name] = $dependency_objects[$name];
            }
          }
        }
      }
    }

    // Now for all plugins with optional dependencies (stored in
    // $call_on_removal, mapped to their removed dependencies) call their
    // onDependencyRemoval() methods.
    $updated_config = [];
    foreach ($call_on_removal as $plugin_type => $plugins) {
      foreach ($plugins as $plugin_id => $plugin_dependencies) {
        $removal_successful = $all_plugins[$plugin_type][$plugin_id]
          ->onDependencyRemoval($plugin_dependencies);

        // If the plugin was successfully changed to remove the dependency,
        // remember the new configuration to later set it. Otherwise, remove the
        // plugin from the index so the dependency still gets removed.
        if ($removal_successful) {
          $updated_config[$plugin_type][$plugin_id] = $all_plugins[$plugin_type][$plugin_id]
            ->getConfiguration();
        }
        else {
          unset($all_plugins[$plugin_type][$plugin_id]);
        }
      }
    }

    // The handling of how we translate plugin changes back to the index varies
    // according to plugin type, unfortunately.
    // First, remove plugins that need to be removed.
    $this->processor_settings = array_intersect_key($this->processor_settings, $all_plugins['processors']);
    $this->processorInstances = array_intersect_key($this->processorInstances, $all_plugins['processors']);
    $this->datasource_settings = array_intersect_key($this->datasource_settings, $all_plugins['datasources']);
    $this->datasourceInstances = array_intersect_key($this->datasourceInstances, $all_plugins['datasources']);

    // There always needs to be a tracker so reset it back to the default
    // tracker.
    if (empty($all_plugins['tracker'])) {
      $default_tracker_id = \Drupal::config('search_api.settings')
        ->get('default_tracker');
      $this->tracker_settings = [
        $default_tracker_id => [],
      ];

      // Reset $trackerInstance so it will get newly loaded from our reset
      // settings when required.
      $this->trackerInstance = NULL;
    }

    // There also always needs to be a datasource, but here we have no easy way
    // out – if we had to remove all datasources, the operation fails. Return
    // FALSE to indicate this, which will cause the index to be deleted.
    if (!$this->datasource_settings) {
      return FALSE;
    }

    // Then, update configuration as necessary.
    foreach ($updated_config as $plugin_type => $plugin_configs) {
      foreach ($plugin_configs as $plugin_id => $plugin_config) {
        switch ($plugin_type) {
          case 'processors':
            $this->processor_settings[$plugin_id] = $plugin_config;
            break;
          case 'datasources':
            $this->datasource_settings[$plugin_id] = $plugin_config;
            break;
          case 'tracker':
            $this->tracker_settings[$plugin_id] = $plugin_config;
            break;
        }
      }
    }
    return $changed;
  }

  /**
   * Retrieves all the plugins contained in this index.
   *
   * @return \Drupal\search_api\Plugin\IndexPluginInterface[][]
   *   All plugins contained in this index, keyed by their property on the index
   *   and their plugin ID.
   */
  protected function getAllPlugins() {
    $plugins = [];
    if ($this
      ->hasValidTracker()) {
      $plugins['tracker'][$this
        ->getTrackerId()] = $this
        ->getTrackerInstance();
    }
    $plugins['processors'] = $this
      ->getProcessors();
    $plugins['datasources'] = $this
      ->getDatasources();
    return $plugins;
  }

  /**
   * Implements the magic __sleep() method.
   *
   * Prevents the instantiated plugins and fields from being serialized.
   */
  public function __sleep() {

    // First, write our changes to the persistent *_settings properties so they
    // won't be discarded. Make sure we have a container to do this. This is
    // important to correctly display test failures.
    if (\Drupal::hasContainer()) {
      $this
        ->writeChangesToSettings();
    }

    // Then, return a list of all properties that don't contain objects.
    $properties = get_object_vars($this);
    unset($properties['datasourceInstances']);
    unset($properties['trackerInstance']);
    unset($properties['serverInstance']);
    unset($properties['processorInstances']);
    unset($properties['fieldInstances']);
    unset($properties['properties']);
    return array_keys($properties);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CacheableDependencyTrait::$cacheContexts protected property Cache contexts.
CacheableDependencyTrait::$cacheMaxAge protected property Cache max-age.
CacheableDependencyTrait::$cacheTags protected property Cache tags.
CacheableDependencyTrait::setCacheability protected function Sets cacheability; useful for value object constructors.
ConfigEntityBase::$isUninstalling private property Whether the config is being deleted by the uninstall process.
ConfigEntityBase::$langcode protected property The language code of the entity's default language.
ConfigEntityBase::$originalId protected property The original ID of the configuration entity.
ConfigEntityBase::$status protected property The enabled/disabled status of the configuration entity. 4
ConfigEntityBase::$third_party_settings protected property Third party entity settings.
ConfigEntityBase::$trustedData protected property Trust supplied data and not use configuration schema on save.
ConfigEntityBase::$uuid protected property The UUID for this entity.
ConfigEntityBase::$_core protected property Information maintained by Drupal core about configuration.
ConfigEntityBase::addDependency protected function Overrides \Drupal\Core\Entity\DependencyTrait:addDependency().
ConfigEntityBase::createDuplicate public function Creates a duplicate of the entity. Overrides EntityBase::createDuplicate 1
ConfigEntityBase::disable public function Disables the configuration entity. Overrides ConfigEntityInterface::disable 1
ConfigEntityBase::enable public function Enables the configuration entity. Overrides ConfigEntityInterface::enable
ConfigEntityBase::get public function Returns the value of a property. Overrides ConfigEntityInterface::get
ConfigEntityBase::getCacheTagsToInvalidate public function Returns the cache tags that should be used to invalidate caches. Overrides EntityBase::getCacheTagsToInvalidate 1
ConfigEntityBase::getConfigDependencyName public function Gets the configuration dependency name. Overrides EntityBase::getConfigDependencyName
ConfigEntityBase::getConfigManager protected static function Gets the configuration manager.
ConfigEntityBase::getConfigTarget public function Gets the configuration target identifier for the entity. Overrides EntityBase::getConfigTarget
ConfigEntityBase::getDependencies public function Gets the configuration dependencies. Overrides ConfigEntityInterface::getDependencies
ConfigEntityBase::getOriginalId public function Gets the original ID. Overrides EntityBase::getOriginalId
ConfigEntityBase::getThirdPartyProviders public function Gets the list of third parties that store information. Overrides ThirdPartySettingsInterface::getThirdPartyProviders
ConfigEntityBase::getThirdPartySetting public function Gets the value of a third-party setting. Overrides ThirdPartySettingsInterface::getThirdPartySetting
ConfigEntityBase::getThirdPartySettings public function Gets all third-party settings of a given module. Overrides ThirdPartySettingsInterface::getThirdPartySettings
ConfigEntityBase::getTypedConfig protected function Gets the typed config manager.
ConfigEntityBase::hasTrustedData public function Gets whether on not the data is trusted. Overrides ConfigEntityInterface::hasTrustedData
ConfigEntityBase::invalidateTagsOnDelete protected static function Override to never invalidate the individual entities' cache tags; the config system already invalidates them. Overrides EntityBase::invalidateTagsOnDelete
ConfigEntityBase::invalidateTagsOnSave protected function Override to never invalidate the entity's cache tag; the config system already invalidates it. Overrides EntityBase::invalidateTagsOnSave
ConfigEntityBase::isInstallable public function Checks whether this entity is installable. Overrides ConfigEntityInterface::isInstallable 2
ConfigEntityBase::isUninstalling public function Returns whether this entity is being changed during the uninstall process. Overrides ConfigEntityInterface::isUninstalling
ConfigEntityBase::link public function Deprecated way of generating a link to the entity. See toLink(). Overrides EntityBase::link
ConfigEntityBase::save public function Saves an entity permanently. Overrides EntityBase::save 1
ConfigEntityBase::set public function Sets the value of a property. Overrides ConfigEntityInterface::set
ConfigEntityBase::setOriginalId public function Sets the original ID. Overrides EntityBase::setOriginalId
ConfigEntityBase::setStatus public function Sets the status of the configuration entity. Overrides ConfigEntityInterface::setStatus
ConfigEntityBase::setThirdPartySetting public function Sets the value of a third-party setting. Overrides ThirdPartySettingsInterface::setThirdPartySetting
ConfigEntityBase::setUninstalling public function
ConfigEntityBase::sort public static function Helper callback for uasort() to sort configuration entities by weight and label. 6
ConfigEntityBase::status public function Returns whether the configuration entity is enabled. Overrides ConfigEntityInterface::status 4
ConfigEntityBase::toArray public function Gets an array of all property values. Overrides EntityBase::toArray 2
ConfigEntityBase::toUrl public function Gets the URL object for the entity. Overrides EntityBase::toUrl
ConfigEntityBase::trustData public function Sets that the data should be trusted. Overrides ConfigEntityInterface::trustData
ConfigEntityBase::unsetThirdPartySetting public function Unsets a third-party setting. Overrides ThirdPartySettingsInterface::unsetThirdPartySetting
ConfigEntityBase::url public function Gets the public URL for this entity. Overrides EntityBase::url
ConfigEntityBase::urlInfo public function Gets the URL object for the entity. Overrides EntityBase::urlInfo
ConfigEntityBase::__construct public function Constructs an Entity object. Overrides EntityBase::__construct 10
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function Aliased as: traitSleep 1
DependencySerializationTrait::__wakeup public function 2
DependencyTrait::$dependencies protected property The object's dependencies.
DependencyTrait::addDependencies protected function Adds multiple dependencies.
DependencyTrait::addDependency protected function Adds a dependency. Aliased as: addDependencyTrait
EntityBase::$enforceIsNew protected property Boolean indicating whether the entity should be forced to be new.
EntityBase::$entityTypeId protected property The entity type.
EntityBase::$typedData protected property A typed data object wrapping this entity.
EntityBase::access public function Checks data value access. Overrides AccessibleInterface::access 1
EntityBase::bundle public function Gets the bundle of the entity. Overrides EntityInterface::bundle 1
EntityBase::create public static function Constructs a new entity object, without permanently saving it. Overrides EntityInterface::create
EntityBase::delete public function Deletes an entity permanently. Overrides EntityInterface::delete 2
EntityBase::enforceIsNew public function Enforces an entity to be new. Overrides EntityInterface::enforceIsNew
EntityBase::entityManager Deprecated protected function Gets the entity manager.
EntityBase::entityTypeBundleInfo protected function Gets the entity type bundle info service.
EntityBase::entityTypeManager protected function Gets the entity type manager.
EntityBase::getCacheContexts public function The cache contexts associated with this object. Overrides CacheableDependencyTrait::getCacheContexts
EntityBase::getCacheMaxAge public function The maximum age for which this object may be cached. Overrides CacheableDependencyTrait::getCacheMaxAge
EntityBase::getCacheTags public function The cache tags associated with this object. Overrides CacheableDependencyTrait::getCacheTags
EntityBase::getConfigDependencyKey public function Gets the key that is used to store configuration dependencies. Overrides EntityInterface::getConfigDependencyKey
EntityBase::getEntityType public function Gets the entity type definition. Overrides EntityInterface::getEntityType
EntityBase::getEntityTypeId public function Gets the ID of the type of the entity. Overrides EntityInterface::getEntityTypeId
EntityBase::getListCacheTagsToInvalidate protected function The list cache tags to invalidate for this entity.
EntityBase::getTypedData public function Gets a typed data object for this entity object. Overrides EntityInterface::getTypedData
EntityBase::hasLinkTemplate public function Indicates if a link template exists for a given key. Overrides EntityInterface::hasLinkTemplate
EntityBase::label public function Gets the label of the entity. Overrides EntityInterface::label 6
EntityBase::language public function Gets the language of the entity. Overrides EntityInterface::language 1
EntityBase::languageManager protected function Gets the language manager.
EntityBase::linkTemplates protected function Gets an array link templates. 1
EntityBase::load public static function Loads an entity. Overrides EntityInterface::load
EntityBase::loadMultiple public static function Loads one or more entities. Overrides EntityInterface::loadMultiple
EntityBase::postLoad public static function Acts on loaded entities. Overrides EntityInterface::postLoad 2
EntityBase::preCreate public static function Changes the values of an entity before it is created. Overrides EntityInterface::preCreate 5
EntityBase::referencedEntities public function Gets a list of entities referenced by this entity. Overrides EntityInterface::referencedEntities 1
EntityBase::toLink public function Generates the HTML for a link to this entity. Overrides EntityInterface::toLink
EntityBase::uriRelationships public function Gets a list of URI relationships supported by this entity. Overrides EntityInterface::uriRelationships
EntityBase::urlRouteParameters protected function Gets an array of placeholders for this entity. 2
EntityBase::uuid public function Gets the entity UUID (Universally Unique Identifier). Overrides EntityInterface::uuid 1
EntityBase::uuidGenerator protected function Gets the UUID generator.
Index::$batchTracking protected property The number of currently active "batch tracking" modes.
Index::$datasourceInstances protected property The instantiated datasource plugins.
Index::$datasource_settings protected property The settings of the datasources selected for this index.
Index::$description protected property A string describing the index.
Index::$fieldInstances protected property An array of field instances.
Index::$field_settings protected property An array of field settings.
Index::$id protected property The ID of the index.
Index::$name protected property A name to be displayed for the index.
Index::$options protected property An array of options configuring this index.
Index::$processorInstances protected property Instances of the processor plugins.
Index::$processor_settings protected property The array of processor settings.
Index::$properties protected property Static cache of retrieved property definitions, grouped by datasource.
Index::$read_only protected property A flag indicating whether to write to this index.
Index::$server protected property The ID of the server on which data should be indexed.
Index::$serverInstance protected property The server entity belonging to this index.
Index::$trackerInstance protected property The tracker plugin instance.
Index::$tracker_settings protected property The tracker settings.
Index::addDatasource public function Adds a datasource to this index. Overrides IndexInterface::addDatasource
Index::addField public function Adds a field to this index. Overrides IndexInterface::addField
Index::addProcessor public function Adds a processor to this index. Overrides IndexInterface::addProcessor
Index::alterIndexedItems public function Alter the items to be indexed. Overrides IndexInterface::alterIndexedItems
Index::calculateDependencies public function Calculates dependencies and stores them in the dependency property. Overrides ConfigEntityBase::calculateDependencies
Index::clear public function Clears all indexed data from this index and marks it for reindexing. Overrides IndexInterface::clear
Index::discardFieldChanges public function Resets the index's fields to the saved state. Overrides IndexInterface::discardFieldChanges
Index::getAllPlugins protected function Retrieves all the plugins contained in this index.
Index::getDatasource public function Retrieves a specific datasource plugin for this index. Overrides IndexInterface::getDatasource
Index::getDatasourceIds public function Retrieves the IDs of all datasources enabled for this index. Overrides IndexInterface::getDatasourceIds
Index::getDatasources public function Retrieves this index's datasource plugins. Overrides IndexInterface::getDatasources
Index::getDependencyData protected function Retrieves data about this index's dependencies.
Index::getDescription public function Retrieves the index description. Overrides IndexInterface::getDescription
Index::getEntityTypes public function Retrieves all entity types contained in this index. Overrides IndexInterface::getEntityTypes
Index::getField public function Returns a field from this index. Overrides IndexInterface::getField
Index::getFieldDependencies protected function Retrieves information about the dependencies of the indexed fields.
Index::getFieldRenames public function Retrieves all field IDs that changed compared to the index's saved version. Overrides IndexInterface::getFieldRenames
Index::getFields public function Returns a list of all indexed fields of this index. Overrides IndexInterface::getFields
Index::getFieldsByDatasource public function Returns a list of all indexed fields of a specific datasource. Overrides IndexInterface::getFieldsByDatasource
Index::getFulltextFields public function Retrieves all of this index's fulltext fields. Overrides IndexInterface::getFulltextFields
Index::getOption public function Retrieves an option. Overrides IndexInterface::getOption
Index::getOptions public function Retrieves an array of all options. Overrides IndexInterface::getOptions
Index::getProcessor public function Retrieves a specific processor plugin for this index. Overrides IndexInterface::getProcessor
Index::getProcessors public function Retrieves this index's processors. Overrides IndexInterface::getProcessors
Index::getProcessorsByStage public function Loads this index's processors for a specific stage. Overrides IndexInterface::getProcessorsByStage
Index::getPropertyDefinitions public function Retrieves the properties of one of this index's datasources. Overrides IndexInterface::getPropertyDefinitions
Index::getServerId public function Retrieves the ID of the server the index is attached to. Overrides IndexInterface::getServerId
Index::getServerInstance public function Retrieves the server the index is attached to. Overrides IndexInterface::getServerInstance
Index::getTrackerId public function Retrieves the tracker plugin's ID. Overrides IndexInterface::getTrackerId
Index::getTrackerInstance public function Retrieves the tracker plugin. Overrides IndexInterface::getTrackerInstance
Index::hasValidServer public function Determines whether this index is lying on a valid server. Overrides IndexInterface::hasValidServer
Index::hasValidTracker public function Determines whether the tracker is valid. Overrides IndexInterface::hasValidTracker
Index::id public function Gets the identifier. Overrides EntityBase::id
Index::indexItems public function Indexes a set amount of items. Overrides IndexInterface::indexItems
Index::indexSpecificItems public function Indexes some objects on this index. Overrides IndexInterface::indexSpecificItems
Index::isBatchTracking public function Determines whether the index is currently in "batch tracking" mode. Overrides IndexInterface::isBatchTracking
Index::isReadOnly public function Determines whether this index is read-only. Overrides IndexInterface::isReadOnly
Index::isReindexing public function Determines whether reindexing has been triggered in this page request. Overrides IndexInterface::isReindexing
Index::isServerEnabled public function Checks if this index has an enabled server. Overrides IndexInterface::isServerEnabled
Index::isValidDatasource public function Determines whether the given datasource ID is valid for this index. Overrides IndexInterface::isValidDatasource
Index::isValidProcessor public function Determines whether the given processor ID is valid for this index. Overrides IndexInterface::isValidProcessor
Index::loadItem public function Loads a single search object of this index. Overrides IndexInterface::loadItem
Index::loadItemsMultiple public function Loads multiple search objects for this index. Overrides IndexInterface::loadItemsMultiple
Index::onDependencyRemoval public function Informs the entity that entities it depends on will be deleted. Overrides ConfigEntityBase::onDependencyRemoval
Index::postCreate public function Acts on a created entity before hooks are invoked. Overrides EntityBase::postCreate
Index::postDelete public static function Acts on deleted entities before the delete hook is invoked. Overrides EntityBase::postDelete
Index::postprocessSearchResults public function Postprocesses search results before they are displayed. Overrides IndexInterface::postprocessSearchResults
Index::postSave public function Acts on a saved entity before the insert or update hook is invoked. Overrides EntityBase::postSave
Index::preDelete public static function Acts on entities before they are deleted and before hooks are invoked. Overrides ConfigEntityBase::preDelete
Index::preprocessIndexItems public function Preprocesses data items for indexing. Overrides IndexInterface::preprocessIndexItems
Index::preprocessSearchQuery public function Preprocesses a search query. Overrides IndexInterface::preprocessSearchQuery
Index::preSave public function Acts on an entity before the presave hook is invoked. Overrides ConfigEntityBase::preSave
Index::query public function Creates a query object for this index. Overrides IndexInterface::query
Index::reactToDatasourceSwitch protected function Checks whether the index's datasources changed and reacts accordingly.
Index::reactToProcessorChanges protected function Reacts to changes in processor configuration.
Index::reactToServerSwitch protected function Checks whether the index switched server and reacts accordingly.
Index::reactToTrackerSwitch protected function Checks whether the index switched tracker plugin and reacts accordingly.
Index::rebuildTracker public function Starts a rebuild of the index's tracking information. Overrides IndexInterface::rebuildTracker
Index::reindex public function Marks all items in this index for reindexing. Overrides IndexInterface::reindex
Index::removeDatasource public function Removes a datasource from this index. Overrides IndexInterface::removeDatasource
Index::removeField public function Removes a field from the index. Overrides IndexInterface::removeField
Index::removeProcessor public function Removes a processor from this index. Overrides IndexInterface::removeProcessor
Index::renameField public function Changes the field ID of a field. Overrides IndexInterface::renameField
Index::setDatasources public function Sets this index's datasource plugins. Overrides IndexInterface::setDatasources
Index::setFields public function Sets this index's fields. Overrides IndexInterface::setFields
Index::setHasReindexed protected function Sets whether this index has all items marked for re-indexing.
Index::setOption public function Sets an option. Overrides IndexInterface::setOption
Index::setOptions public function Sets the index's options. Overrides IndexInterface::setOptions
Index::setProcessors public function Sets this index's processor plugins. Overrides IndexInterface::setProcessors
Index::setServer public function Sets the server the index is attached to. Overrides IndexInterface::setServer
Index::setTracker public function Sets the tracker the index uses. Overrides IndexInterface::setTracker
Index::startBatchTracking public function Puts the index into "batch tracking" mode. Overrides IndexInterface::startBatchTracking
Index::stopBatchTracking public function Stop the latest initialized "batch tracking" mode for the index. Overrides IndexInterface::stopBatchTracking
Index::trackItemsDeleted public function Deletes items from the index. Overrides IndexInterface::trackItemsDeleted
Index::trackItemsInserted public function Adds items from a specific datasource to the index. Overrides IndexInterface::trackItemsInserted
Index::trackItemsInsertedOrUpdated protected function Tracks insertion or updating of items.
Index::trackItemsUpdated public function Updates items from a specific datasource present in the index. Overrides IndexInterface::trackItemsUpdated
Index::writeChangesToSettings protected function Prepares for changes to this index to be persisted.
Index::__sleep public function Implements the magic __sleep() method. Overrides ConfigEntityBase::__sleep
IndexInterface::DATASOURCE_ID_SEPARATOR constant String used to separate a datasource prefix from the rest of an identifier.
IndexInterface::PROPERTY_PATH_SEPARATOR constant String used to separate individual properties within a property path.
InstallingTrait::isInstallingFromExtension protected function Determines if this config entity is being installed from an extension.
InstallingTrait::isNew abstract public function Determines whether the entity is new.
LoggerTrait::$logger protected property The logging channel to use.
LoggerTrait::getLogger public function Retrieves the logger.
LoggerTrait::logException protected function Logs an exception.
LoggerTrait::setLogger public function Sets the logger.
PluginDependencyTrait::calculatePluginDependencies protected function Calculates and adds dependencies of a specific plugin instance. 1
PluginDependencyTrait::getPluginDependencies protected function Calculates and returns dependencies of a specific plugin instance.
PluginDependencyTrait::moduleHandler protected function Wraps the module handler. 1
PluginDependencyTrait::themeHandler protected function Wraps the theme handler. 1
RefinableCacheableDependencyTrait::addCacheableDependency public function 1
RefinableCacheableDependencyTrait::addCacheContexts public function
RefinableCacheableDependencyTrait::addCacheTags public function
RefinableCacheableDependencyTrait::mergeCacheMaxAge public function
SynchronizableEntityTrait::$isSyncing protected property Whether this entity is being created, updated or deleted through a synchronization process.
SynchronizableEntityTrait::isSyncing public function
SynchronizableEntityTrait::setSyncing public function