View source
<?php
namespace Drupal\search_api\Entity;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\search_api\Event\DeterminingServerFeaturesEvent;
use Drupal\search_api\Event\SearchApiEvents;
use Drupal\search_api\IndexInterface;
use Drupal\search_api\LoggerTrait;
use Drupal\search_api\Query\QueryInterface;
use Drupal\search_api\SearchApiException;
use Drupal\search_api\ServerInterface;
use Drupal\search_api\Utility\Utility;
class Server extends ConfigEntityBase implements ServerInterface {
use InstallingTrait;
use LoggerTrait;
protected $id;
protected $name;
protected $description = '';
protected $backend;
protected $backend_config = [];
protected $backendPlugin;
protected $features;
public function getDescription() {
return $this->description;
}
public function hasValidBackend() {
$backend_plugin_definition = \Drupal::service('plugin.manager.search_api.backend')
->getDefinition($this
->getBackendId(), FALSE);
return !empty($backend_plugin_definition);
}
public function getBackendId() {
return $this->backend;
}
public function getBackend() {
if (!$this->backendPlugin) {
$backend_plugin_manager = \Drupal::service('plugin.manager.search_api.backend');
$config = $this->backend_config;
$config['#server'] = $this;
if (!($this->backendPlugin = $backend_plugin_manager
->createInstance($this
->getBackendId(), $config))) {
$backend_id = $this
->getBackendId();
$label = $this
->label();
throw new SearchApiException("The backend with ID '{$backend_id}' could not be retrieved for server '{$label}'.");
}
}
return $this->backendPlugin;
}
public function getBackendConfig() {
return $this->backend_config;
}
public function setBackendConfig(array $backend_config) {
$this->backend_config = $backend_config;
if ($this->backendPlugin && $this
->getBackend()
->getConfiguration() !== $backend_config) {
$this
->getBackend()
->setConfiguration($backend_config);
}
return $this;
}
public function getIndexes(array $properties = []) {
$storage = \Drupal::entityTypeManager()
->getStorage('search_api_index');
return $storage
->loadByProperties([
'server' => $this
->id(),
] + $properties);
}
public function viewSettings() {
return $this
->hasValidBackend() ? $this
->getBackend()
->viewSettings() : [];
}
public function isAvailable() {
return $this
->hasValidBackend() ? $this
->getBackend()
->isAvailable() : FALSE;
}
public function supportsFeature($feature) {
return in_array($feature, $this
->getSupportedFeatures());
}
public function getSupportedFeatures() {
if (!isset($this->features)) {
$this->features = [];
if ($this
->hasValidBackend()) {
$this->features = $this
->getBackend()
->getSupportedFeatures();
}
$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.determining_server_features" event instead. See https://www.drupal.org/node/3059866';
\Drupal::moduleHandler()
->alterDeprecated($description, 'search_api_server_features', $this->features, $this);
$eventDispatcher = \Drupal::getContainer()
->get('event_dispatcher');
$eventDispatcher
->dispatch(SearchApiEvents::DETERMINING_SERVER_FEATURES, new DeterminingServerFeaturesEvent($this->features, $this));
}
return $this->features;
}
public function supportsDataType($type) {
if ($this
->hasValidBackend()) {
return $this
->getBackend()
->supportsDataType($type);
}
return FALSE;
}
public function getDiscouragedProcessors() {
if ($this
->hasValidBackend()) {
return $this
->getBackend()
->getDiscouragedProcessors();
}
return [];
}
public function getBackendDefinedFields(IndexInterface $index) {
if ($this
->hasValidBackend()) {
return $this
->getBackend()
->getBackendDefinedFields($index);
}
return [];
}
public function addIndex(IndexInterface $index) {
$server_task_manager = \Drupal::getContainer()
->get('search_api.server_task_manager');
$server_task_manager
->delete($this, $index);
try {
if ($server_task_manager
->execute($this)) {
$this
->getBackend()
->addIndex($index);
return;
}
} catch (SearchApiException $e) {
$vars = [
'%server' => $this
->label(),
'%index' => $index
->label(),
];
$this
->logException($e, '%type while adding index %index to server %server: @message in %function (line %line of %file).', $vars);
}
$task_manager = \Drupal::getContainer()
->get('search_api.task_manager');
$task_manager
->addTask(__FUNCTION__, $this, $index);
}
public function updateIndex(IndexInterface $index) {
$server_task_manager = \Drupal::getContainer()
->get('search_api.server_task_manager');
try {
if ($server_task_manager
->execute($this)) {
$this
->getBackend()
->updateIndex($index);
return;
}
} catch (SearchApiException $e) {
$vars = [
'%server' => $this
->label(),
'%index' => $index
->label(),
];
$this
->logException($e, '%type while updating the fields of index %index on server %server: @message in %function (line %line of %file).', $vars);
}
$task_manager = \Drupal::getContainer()
->get('search_api.task_manager');
$task_manager
->addTask(__FUNCTION__, $this, $index, $index->original ?? NULL);
}
public function removeIndex($index) {
$server_task_manager = \Drupal::getContainer()
->get('search_api.server_task_manager');
$server_task_manager
->delete($this, $index);
try {
if ($server_task_manager
->execute($this)) {
$this
->getBackend()
->removeIndex($index);
return;
}
} catch (SearchApiException $e) {
$vars = [
'%server' => $this
->label(),
'%index' => is_object($index) ? $index
->label() : $index,
];
$this
->logException($e, '%type while removing index %index from server %server: @message in %function (line %line of %file).', $vars);
}
$task_manager = \Drupal::getContainer()
->get('search_api.task_manager');
$data = NULL;
if (!is_object($index)) {
$data = $index;
$index = NULL;
}
$task_manager
->addTask(__FUNCTION__, $this, $index, $data);
}
public function indexItems(IndexInterface $index, array $items) {
$server_task_manager = \Drupal::getContainer()
->get('search_api.server_task_manager');
if ($server_task_manager
->execute($this)) {
return $this
->getBackend()
->indexItems($index, $items);
}
$index_label = $index
->label();
throw new SearchApiException("Could not index items on index '{$index_label}' because pending server tasks could not be executed.");
}
public function deleteItems(IndexInterface $index, array $item_ids) {
if ($index
->isReadOnly()) {
$vars = [
'%index' => $index
->label(),
];
$this
->getLogger()
->warning('Trying to delete items from index %index which is marked as read-only.', $vars);
return;
}
$server_task_manager = \Drupal::getContainer()
->get('search_api.server_task_manager');
try {
if ($server_task_manager
->execute($this)) {
$this
->getBackend()
->deleteItems($index, $item_ids);
Cache::invalidateTags([
'search_api_list:' . $index
->id(),
]);
return;
}
} catch (SearchApiException $e) {
$vars = [
'%server' => $this
->label(),
];
$this
->logException($e, '%type while deleting items from server %server: @message in %function (line %line of %file).', $vars);
}
$task_manager = \Drupal::getContainer()
->get('search_api.task_manager');
$task_manager
->addTask(__FUNCTION__, $this, $index, $item_ids);
}
public function deleteAllIndexItems(IndexInterface $index, $datasource_id = NULL) {
if ($index
->isReadOnly()) {
$vars = [
'%index' => $index
->label(),
];
$this
->getLogger()
->warning('Trying to delete items from index %index which is marked as read-only.', $vars);
return;
}
$server_task_manager = \Drupal::getContainer()
->get('search_api.server_task_manager');
if (!$datasource_id) {
$types = [
'deleteItems',
'deleteAllIndexItems',
];
$server_task_manager
->delete($this, $index, $types);
}
try {
if ($server_task_manager
->execute($this)) {
$this
->getBackend()
->deleteAllIndexItems($index, $datasource_id);
Cache::invalidateTags([
'search_api_list:' . $index
->id(),
]);
return;
}
} catch (SearchApiException $e) {
$vars = [
'%server' => $this
->label(),
'%index' => $index
->label(),
];
$this
->logException($e, '%type while deleting items of index %index from server %server: @message in %function (line %line of %file).', $vars);
}
$task_manager = \Drupal::getContainer()
->get('search_api.task_manager');
$task_manager
->addTask(__FUNCTION__, $this, $index, $datasource_id);
}
public function deleteAllItems() {
$failed = [];
$properties['status'] = TRUE;
$properties['read_only'] = FALSE;
foreach ($this
->getIndexes($properties) as $index) {
try {
$this
->getBackend()
->deleteAllIndexItems($index);
Cache::invalidateTags([
'search_api_list:' . $index
->id(),
]);
} catch (SearchApiException $e) {
$args = [
'%index' => $index
->label(),
];
$this
->logException($e, '%type while deleting all items from index %index: @message in %function (line %line of %file).', $args);
$failed[] = $index
->label();
}
}
if (!empty($e)) {
$server_name = $this
->label();
$failed = implode(', ', $failed);
throw new SearchApiException("Deleting all items from server '{$server_name}' failed for the following (write-enabled) indexes: {$failed}.", 0, $e);
}
$types = [
'deleteItems',
'deleteAllIndexItems',
];
\Drupal::getContainer()
->get('search_api.server_task_manager')
->delete($this, NULL, $types);
}
public function search(QueryInterface $query) {
$this
->getBackend()
->search($query);
}
public function preSave(EntityStorageInterface $storage) {
parent::preSave($storage);
if (!isset($this->original)) {
return;
}
$overrides = Utility::getConfigOverrides($this);
if (isset($overrides['backend']) || isset($overrides['backend_config'])) {
$backend_config = $this
->getBackendConfig();
if (isset($overrides['backend_config'])) {
$backend_config = $overrides['backend_config'];
}
$backend_id = $this
->getBackendId();
if (isset($overrides['backend'])) {
$backend_id = $overrides['backend'];
}
$backend_plugin_manager = \Drupal::service('plugin.manager.search_api.backend');
$backend_config['#server'] = $this;
if (!($backend = $backend_plugin_manager
->createInstance($backend_id, $backend_config))) {
$label = $this
->label();
throw new SearchApiException("The backend with ID '{$backend_id}' could not be retrieved for server '{$label}'.");
}
}
else {
$backend = $this
->getBackend();
}
$backend
->preUpdate();
if (!$this
->isSyncing() && !$this
->isInstallingFromExtension() && !isset($overrides['status']) && !$this
->status() && $this->original
->status()) {
foreach ($this
->getIndexes([
'status' => TRUE,
]) as $index) {
$index
->setStatus(FALSE)
->save();
}
}
}
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
if ($this
->hasValidBackend()) {
if ($update) {
$reindexing_necessary = $this
->getBackend()
->postUpdate();
if ($reindexing_necessary) {
foreach ($this
->getIndexes() as $index) {
$index
->reindex();
}
}
}
else {
$this
->getBackend()
->postInsert();
}
}
}
public static function preDelete(EntityStorageInterface $storage, array $entities) {
parent::preDelete($storage, $entities);
foreach ($entities as $server) {
if ($server
->hasValidBackend()) {
$server
->getBackend()
->preDelete();
}
\Drupal::getContainer()
->get('search_api.server_task_manager')
->delete($server);
}
}
public function calculateDependencies() {
parent::calculateDependencies();
if ($this
->hasValidBackend()) {
$this
->calculatePluginDependencies($this
->getBackend());
}
return $this;
}
public function onDependencyRemoval(array $dependencies) {
$changed = parent::onDependencyRemoval($dependencies);
if ($this
->hasValidBackend()) {
$removed_backend_dependencies = [];
$backend = $this
->getBackend();
foreach ($backend
->calculateDependencies() as $dependency_type => $list) {
if (isset($dependencies[$dependency_type])) {
$removed_backend_dependencies[$dependency_type] = array_intersect_key($dependencies[$dependency_type], array_flip($list));
}
}
$removed_backend_dependencies = array_filter($removed_backend_dependencies);
if ($removed_backend_dependencies) {
if ($backend
->onDependencyRemoval($removed_backend_dependencies)) {
$this->backend_config = $backend
->getConfiguration();
$changed = TRUE;
}
}
}
return $changed;
}
public function __clone() {
$this->backendPlugin = NULL;
}
}