You are here

search_api.install in Search API 8

Same filename and directory in other branches
  1. 7 search_api.install

Install, update and uninstall functions for the Search API module.

File

search_api.install
View source
<?php

/**
 * @file
 * Install, update and uninstall functions for the Search API module.
 */
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Database\DatabaseException;
use Drupal\Core\Link;
use Drupal\search_api\Entity\Server;
use Drupal\Core\Url;
use Drupal\search_api\Entity\TaskStorageSchema;

/**
 * Implements hook_schema().
 */
function search_api_schema() {
  $schema['search_api_item'] = [
    'description' => 'Stores the items which should be indexed for each index, and their state.',
    'fields' => [
      'index_id' => [
        'description' => 'The ID of the index this item belongs to',
        'type' => 'varchar',
        'length' => 50,
        'not null' => TRUE,
      ],
      'datasource' => [
        'description' => 'The plugin ID of the datasource this item belongs to',
        'type' => 'varchar',
        'length' => 50,
        'not null' => TRUE,
      ],
      'item_id' => [
        'description' => 'The unique identifier of this item',
        'type' => 'varchar',
        'length' => 150,
        'not null' => TRUE,
      ],
      'changed' => [
        'description' => 'A timestamp indicating when the item was last changed',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ],
      'status' => [
        'description' => 'Boolean indicating the reindexation status, "1" when we need to reindex, "0" otherwise',
        'type' => 'int',
        'not null' => TRUE,
      ],
    ],
    'indexes' => [
      'indexing' => [
        'index_id',
        'status',
        'changed',
        'item_id',
      ],
    ],
    'primary key' => [
      'index_id',
      'item_id',
    ],
  ];
  return $schema;
}

/**
 * Implements hook_uninstall().
 */
function search_api_uninstall() {
  \Drupal::state()
    ->delete('search_api_use_tracking_batch');
  foreach (\Drupal::configFactory()
    ->listAll('search_api.index.') as $index_id) {
    \Drupal::state()
      ->delete("search_api.index.{$index_id}.has_reindexed");
  }
}

/**
 * Implements hook_requirements().
 */
function search_api_requirements($phase) {
  if ($phase == 'runtime') {
    $requirements = [];
    $message = _search_api_search_module_warning();
    if ($message) {
      $requirements += [
        'search_api_core_search' => [
          'title' => t('Search API'),
          'value' => $message,
          'severity' => REQUIREMENT_WARNING,
        ],
      ];
    }

    /** @var \Drupal\search_api\ServerInterface[] $servers */
    $servers = Server::loadMultiple();
    $unavailable_servers = [];
    foreach ($servers as $server) {
      if ($server
        ->status() && !$server
        ->isAvailable()) {
        $unavailable_servers[] = $server
          ->label();
      }
    }
    if (!empty($unavailable_servers)) {
      $requirements += [
        'search_api_server_unavailable' => [
          'title' => t('Search API'),
          'value' => \Drupal::translation()
            ->formatPlural(count($unavailable_servers), 'The search server "@servers" is currently not available', 'The following search servers are not available: @servers', [
            '@servers' => implode(', ', $unavailable_servers),
          ]),
          'severity' => REQUIREMENT_ERROR,
        ],
      ];
    }
    $pending_tasks = \Drupal::getContainer()
      ->get('search_api.task_manager')
      ->getTasksCount();
    if ($pending_tasks) {
      $args['@link'] = '';
      $url = Url::fromRoute('search_api.execute_tasks');
      if ($url
        ->access()) {
        $link = new Link(t('Execute now'), $url);
        $link = $link
          ->toString();
        $args['@link'] = $link;
        $args['@link'] = new FormattableMarkup(' (@link)', $args);
      }
      $requirements['search_api_pending_tasks'] = [
        'title' => t('Search API'),
        'value' => \Drupal::translation()
          ->formatPlural($pending_tasks, 'There is @count pending Search API task. @link', 'There are @count pending Search API tasks. @link', $args),
        'severity' => REQUIREMENT_WARNING,
      ];
    }
    return $requirements;
  }
  return [];
}

/**
 * Adapts index config schema to remove an unnecessary layer for plugins.
 */
function search_api_update_8101() {

  // This update function updates search indexes for the change from
  // https://www.drupal.org/node/2656052.
  $config_factory = \Drupal::configFactory();
  $plugin_types = [
    'processor',
    'datasource',
    'tracker',
  ];
  foreach ($config_factory
    ->listAll('search_api.index.') as $index_id) {
    $index = $config_factory
      ->getEditable($index_id);
    $changed = FALSE;
    foreach ($plugin_types as $plugin_type) {
      $property = $plugin_type . '_settings';
      $plugins = $index
        ->get($property);
      foreach ($plugins as $id => $config) {
        if (isset($config['plugin_id']) && isset($config['settings'])) {
          $changed = TRUE;
          $plugins[$id] = $config['settings'];
        }
      }
      $index
        ->set($property, $plugins);
    }
    if ($changed) {

      // Mark the resulting configuration as trusted data. This avoids issues
      // with future schema changes.
      $index
        ->save(TRUE);
    }
  }
  return t('Index config schema updated.');
}

/**
 * Removes unsupported cache plugins from Search API views.
 */
function search_api_update_8102() {
  $config_factory = \Drupal::configFactory();
  $changed = [];
  foreach ($config_factory
    ->listAll('views.view.') as $view_config_name) {
    $view = $config_factory
      ->getEditable($view_config_name);
    $displays = $view
      ->get('display');
    if ($displays['default']['display_options']['query']['type'] === 'search_api_query') {
      $change = FALSE;
      foreach ($displays as $id => $display) {
        if (in_array($display['display_options']['cache']['type'] ?? '', [
          'tag',
          'time',
        ])) {
          $displays[$id]['display_options']['cache']['type'] = 'none';
          $change = TRUE;
        }
      }
      if ($change) {
        $view
          ->set('display', $displays);

        // Mark the resulting configuration as trusted data. This avoids issues
        // with future schema changes.
        $view
          ->save(TRUE);
        $changed[] = $view
          ->get('id');
      }
    }
  }
  if (!empty($changed)) {
    return \Drupal::translation()
      ->translate('Removed incompatible cache options for the following Search API-based views: @ids', [
      '@ids' => implode(', ', array_unique($changed)),
    ]);
  }
  return NULL;
}

/**
 * Switches from the old "Node status" to the new "Entity status" processor.
 */
function search_api_update_8103() {

  // This update function updates search indexes for the change from
  // https://www.drupal.org/node/2491175.
  $config_factory = \Drupal::configFactory();
  foreach ($config_factory
    ->listAll('search_api.index.') as $index_id) {
    $index = $config_factory
      ->getEditable($index_id);
    $processors = $index
      ->get('processor_settings');
    if (isset($processors['node_status'])) {
      $processors['entity_status'] = $processors['node_status'];
      unset($processors['node_status']);
      $index
        ->set('processor_settings', $processors);

      // Mark the resulting configuration as trusted data. This avoids issues
      // with future schema changes.
      $index
        ->save(TRUE);
    }
  }

  // Clear the processor plugin cache so that if anything else indirectly tries
  // to update Search API-related configuration, the plugin helper gets the most
  // up-to-date plugin definitions.
  \Drupal::getContainer()
    ->get('plugin.manager.search_api.processor')
    ->clearCachedDefinitions();
  return t('Switched from old "Node status" to new "Entity status" processor.');
}

/**
 * Update Views to use the time-based cache plugin for Search API.
 */
function search_api_update_8104() {
  $config_factory = \Drupal::configFactory();
  $changed = [];
  foreach ($config_factory
    ->listAll('views.view.') as $view_config_name) {
    $view = $config_factory
      ->getEditable($view_config_name);
    $displays = $view
      ->get('display');
    $updated = FALSE;
    foreach ($displays as $id => $display) {
      if (($display['display_options']['cache']['type'] ?? '') === 'search_api') {
        $displays[$id]['display_options']['cache']['type'] = 'search_api_time';
        $updated = TRUE;
      }
    }
    if ($updated) {
      $view
        ->set('display', $displays);

      // Mark the resulting configuration as trusted data. This avoids issues
      // with future schema changes.
      $view
        ->save(TRUE);
      $changed[] = $view
        ->get('id');
    }
  }
  if (!empty($changed)) {
    return \Drupal::translation()
      ->translate('The following views have been updated to use the time-based cache plugin: @ids', [
      '@ids' => implode(', ', array_unique($changed)),
    ]);
  }
  return NULL;
}

/**
 * Update the configuration schema of the "Ignore characters" processor.
 */
function search_api_update_8105() {

  // This update function updates search indexes for the change from
  // https://www.drupal.org/node/3007933.
  $config_factory = \Drupal::configFactory();
  $changes = FALSE;
  foreach ($config_factory
    ->listAll('search_api.index.') as $index_id) {
    $index = $config_factory
      ->getEditable($index_id);
    $processors = $index
      ->get('processor_settings');
    if (isset($processors['ignore_character'])) {
      $classes = $processors['ignore_character']['strip']['character_sets'];
      $classes = array_values(array_filter($classes));
      $processors['ignore_character']['ignorable_classes'] = $classes;
      unset($processors['ignore_character']['strip']);
      $index
        ->set('processor_settings', $processors);

      // Mark the resulting configuration as trusted data. This avoids issues
      // with future schema changes.
      $index
        ->save(TRUE);
      $changes = TRUE;
    }
  }
  if ($changes) {
    return t('Updated the configuration schema of the "Ignore characters" processor.');
  }
  return NULL;
}

/**
 * Remove remnants of the search_api_views_taxonomy module.
 */
function search_api_update_8106() {
  try {
    \Drupal::database()
      ->delete('key_value')
      ->condition('collection', 'system.schema')
      ->condition('name', 'search_api_views_taxonomy')
      ->execute();
  } catch (DatabaseException $e) {

    // The admin might have done this already to get rid of the warning
    // themselves. It's not really important enough to fail on this, in any
    // case. In the worst case, the warning just remains. So, just ignore any
    // exception. (Site could also use an alternate key/value store.)
  }
}

/**
 * Add a unique index to the task entity type's storage.
 */
function search_api_update_8107() {
  $manager = \Drupal::entityDefinitionUpdateManager();
  $entity_type = $manager
    ->getEntityType('search_api_task');
  $entity_type
    ->setHandlerClass('storage_schema', TaskStorageSchema::class);
  $manager
    ->updateEntityType($entity_type);
}

/**
 * Add configuration for boost factors.
 */
function search_api_update_8108() {
  $settings = \Drupal::configFactory()
    ->getEditable('search_api.settings');
  $data = $settings
    ->getRawData();
  $data += [
    'boost_factors' => [
      0.0,
      0.1,
      0.2,
      0.3,
      0.5,
      0.6,
      0.7,
      0.8,
      0.9,
      1.0,
      1.1,
      1.2,
      1.3,
      1.4,
      1.5,
      2.0,
      3.0,
      5.0,
      8.0,
      13.0,
      21.0,
    ],
  ];
  $settings
    ->setData($data)
    ->save(TRUE);
}

Functions

Namesort descending Description
search_api_requirements Implements hook_requirements().
search_api_schema Implements hook_schema().
search_api_uninstall Implements hook_uninstall().
search_api_update_8101 Adapts index config schema to remove an unnecessary layer for plugins.
search_api_update_8102 Removes unsupported cache plugins from Search API views.
search_api_update_8103 Switches from the old "Node status" to the new "Entity status" processor.
search_api_update_8104 Update Views to use the time-based cache plugin for Search API.
search_api_update_8105 Update the configuration schema of the "Ignore characters" processor.
search_api_update_8106 Remove remnants of the search_api_views_taxonomy module.
search_api_update_8107 Add a unique index to the task entity type's storage.
search_api_update_8108 Add configuration for boost factors.