You are here

abstract class AbstractSolrEntityListBuilder in Search API Solr 8.3

Same name and namespace in other branches
  1. 4.x src/Controller/AbstractSolrEntityListBuilder.php \Drupal\search_api_solr\Controller\AbstractSolrEntityListBuilder

Provides a listing of Solr Entities.

Hierarchy

Expanded class hierarchy of AbstractSolrEntityListBuilder

1 file declares its use of AbstractSolrEntityListBuilder
SearchApiBackendUnitTest.php in tests/src/Unit/SearchApiBackendUnitTest.php

File

src/Controller/AbstractSolrEntityListBuilder.php, line 14

Namespace

Drupal\search_api_solr\Controller
View source
abstract class AbstractSolrEntityListBuilder extends ConfigEntityListBuilder {
  use BackendTrait;

  /**
   * The label.
   *
   * @var string
   */
  protected $label = '';

  /**
   * The option label.
   *
   * @var string
   */
  protected $option_label = 'Environment';

  /**
   * The default option.
   *
   * @var string
   */
  protected $default_option = 'default';

  /**
   * The number of entities to list per page, or FALSE to list all entities.
   *
   * @var int|false
   */
  protected $limit = FALSE;

  /**
   * {@inheritdoc}
   */
  public function buildHeader() {
    $header = [
      'label' => $this
        ->t('@label', [
        '@before' => $this->label,
      ]),
      'minimum_solr_version' => $this
        ->t('Minimum Solr Version'),
      'option' => $this
        ->t('@optionLabel', [
        '@optionLabel' => $this->option_label,
      ]),
      'id' => $this
        ->t('Machine name'),
      'enabled' => $this
        ->t('Enabled'),
    ];
    return $header + parent::buildHeader();
  }

  /**
   * {@inheritdoc}
   */
  public function buildRow(EntityInterface $solr_entity) {

    /** @var \Drupal\search_api_solr\SolrConfigInterface $solr_entity */
    $options = $solr_entity
      ->getOptions();
    if (empty($options)) {
      $options = [
        $this->default_option,
      ];
    }
    $enabled_label = $solr_entity->disabledOnServer ? $this
      ->t('Disabled') : $this
      ->t('Enabled');
    $enabled_icon = [
      '#theme' => 'image',
      '#uri' => !$solr_entity->disabledOnServer ? 'core/misc/icons/73b355/check.svg' : 'core/misc/icons/e32700/error.svg',
      '#width' => 18,
      '#height' => 18,
      '#alt' => $enabled_label,
      '#title' => $enabled_label,
    ];
    $row = [
      'label' => $solr_entity
        ->label(),
      'minimum_solr_version' => $solr_entity
        ->getMinimumSolrVersion(),
      // @todo format
      'options' => implode(', ', $options),
      'id' => $solr_entity
        ->id(),
      'enabled' => [
        'data' => $enabled_icon,
        'class' => [
          'checkbox',
        ],
      ],
    ];
    return $row + parent::buildRow($solr_entity);
  }

  /**
   * Returns a list of all enabled Solr config entities for current server.
   *
   * @return array
   *   An array of all enabled Solr config entities for current server.
   *
   * @throws \Drupal\search_api_solr\SearchApiSolrConflictingEntitiesException
   * @throws \Drupal\search_api\SearchApiException
   */
  public function getEnabledEntities() : array {
    $solr_entities = [];

    /** @var \Drupal\search_api_solr\SolrConfigInterface[] $entities */
    $entities = $this
      ->load();
    foreach ($this
      ->load() as $solr_entity) {
      if (!$solr_entity->disabledOnServer) {
        $solr_entities[] = $solr_entity;
      }
    }
    if ($conflicting_entities = $this
      ->getConflictingEntities($solr_entities)) {
      $exception = new SearchApiSolrConflictingEntitiesException();
      $exception
        ->setConflictingEntities($conflicting_entities);
      throw $exception;
    }
    return $solr_entities;
  }

  /**
   * {@inheritdoc}
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  public function getDefaultOperations(EntityInterface $solr_entity) {

    /** @var \Drupal\search_api_solr\SolrConfigInterface $solr_entity */
    $operations = parent::getDefaultOperations($solr_entity);
    unset($operations['delete']);
    if (!$solr_entity->disabledOnServer && $solr_entity
      ->access('view') && $solr_entity
      ->hasLinkTemplate('disable-for-server')) {
      $operations['disable_for_server'] = [
        'title' => $this
          ->t('Disable'),
        'weight' => 10,
        'url' => $solr_entity
          ->toUrl('disable-for-server'),
      ];
    }
    if ($solr_entity->disabledOnServer && $solr_entity
      ->access('view') && $solr_entity
      ->hasLinkTemplate('enable-for-server')) {
      $operations['enable_for_server'] = [
        'title' => $this
          ->t('Enable'),
        'weight' => 10,
        'url' => $solr_entity
          ->toUrl('enable-for-server'),
      ];
    }
    return $operations;
  }

  /**
   * Get all disabled entities.
   */
  protected abstract function getDisabledEntities() : array;

  /**
   * {@inheritdoc}
   *
   * @throws \Drupal\search_api\SearchApiException
   */
  public function load() {
    static $entities;
    if (!$entities || $this->reset) {
      $solr_version = '9999.0.0';
      $operator = '>=';
      $option = $this->default_option;
      $warning = FALSE;
      $disabled_entities = [];
      try {

        /** @var \Drupal\search_api_solr\SolrBackendInterface $backend */
        $backend = $this
          ->getBackend();
        $disabled_entities = $this
          ->getDisabledEntities();
        $option = $backend
          ->getEnvironment();
        $solr_version = $backend
          ->getSolrConnector()
          ->getSolrVersion();
        if (version_compare($solr_version, '0.0.0', '==')) {
          $solr_version = '9999.0.0';
          throw new SearchApiSolrException();
        }
      } catch (SearchApiSolrException $e) {
        $operator = '<=';
        $warning = TRUE;
      }

      // We need the whole list to work on.
      $this->limit = FALSE;
      $entity_ids = $this
        ->getEntityIds();

      /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage */
      $storage = $this
        ->getStorage();

      /** @var \Drupal\search_api_solr\SolrConfigInterface[] $entities */
      $entities = $storage
        ->loadMultipleOverrideFree($entity_ids);

      // We filter those entities that are relevant for the current server.
      // There are multiple entities having the same entity name but different
      // values for minimum_solr_version and environment.
      $selection = [];
      foreach ($entities as $key => $entity) {
        $entities[$key]->disabledOnServer = in_array($entity
          ->id(), $disabled_entities);

        /** @var \Drupal\search_api_solr\SolrConfigInterface $entity
         */
        $version = $entity
          ->getMinimumSolrVersion();
        $environments = $entity
          ->getEnvironments();
        if (version_compare($version, $solr_version, '>') || !in_array($option, $environments) && !in_array($this->default_option, $environments)) {
          unset($entities[$key]);
        }
        else {
          $name = $entity
            ->getName();
          if (isset($selection[$name])) {

            // The more specific environment has precedence
            // over a newer version.
            if ($this->default_option !== $option && $this->default_option === $selection[$name]['option'] && in_array($option, $environments) || version_compare($version, $selection[$name]['version'], $operator) && in_array($selection[$name]['option'], $environments)) {
              $this
                ->mergeSolrConfigs($entities[$key], $entities[$selection[$name]['key']]);
              unset($entities[$selection[$name]['key']]);
              $selection[$name] = [
                'version' => $version,
                'key' => $key,
                'option' => in_array($option, $environments) ? $option : $this->default_option,
              ];
            }
            else {
              $this
                ->mergeSolrConfigs($entities[$selection[$name]['key']], $entities[$key]);
              unset($entities[$key]);
            }
          }
          else {
            $selection[$name] = [
              'version' => $version,
              'key' => $key,
              'option' => in_array($option, $environments) ? $option : $this->default_option,
            ];
          }
        }
      }
      if ($warning) {
        $this->assumedMinimumVersion = array_reduce($selection, function ($version, $item) {
          if (version_compare($item['version'], $version, '<')) {
            return $item['version'];
          }
          return $version;
        }, $solr_version);
        \Drupal::messenger()
          ->addWarning($this
          ->t('Unable to reach the Solr server (yet). Therefore the lowest supported Solr version %version is assumed. Once the connection works and the real Solr version could be detected it might be necessary to deploy an adjusted config to the server to get the best search results. If the server does not start using the downloadable config, you should edit the server and manually set the Solr version override temporarily that fits your server best and download the config again. But it is recommended to remove this override once the server is running.', [
          '%version' => $this->assumedMinimumVersion,
        ]));
      }

      // Sort the entities using the entity class's sort() method.
      // See \Drupal\Core\Config\Entity\ConfigEntityBase::sort().
      uasort($entities, [
        $this->entityType
          ->getClass(),
        'sort',
      ]);
      $this->reset = FALSE;
    }
    return $entities;
  }

  /**
   * Merge two Solr config entities.
   *
   * @param \Drupal\search_api_solr\SolrConfigInterface $target
   *   The target Solr config entity.
   * @param \Drupal\search_api_solr\SolrConfigInterface $source
   *   The source Solr config entity.
   */
  protected function mergeSolrConfigs(SolrConfigInterface $target, SolrConfigInterface $source) {
    if (empty($target
      ->getSolrConfigs()) && !empty($source
      ->getSolrConfigs())) {
      $target
        ->setSolrConfigs($source
        ->getSolrConfigs());
    }
  }

  /**
   * Returns the formatted XML for the entities.
   *
   * @return string
   *   The formatted XML for the entities.
   *
   * @throws \Drupal\search_api\SearchApiException
   */
  public function getXml() {
    $xml = '';

    /** @var \Drupal\search_api_solr\SolrConfigInterface $solr_entities */
    foreach ($this
      ->getEnabledEntities() as $solr_entities) {
      $xml .= $solr_entities
        ->getAsXml();
    }
    foreach ($this
      ->load() as $solr_entities) {
      $xml .= $solr_entities
        ->getSolrConfigsAsXml();
    }
    return $xml;
  }

  /**
   * Get all recommended Entities.
   *
   * @return array
   *   An array of all recommended entities.
   *
   * @throws \Drupal\search_api\SearchApiException
   */
  public function getRecommendedEntities() : array {
    $entities = $this
      ->load();
    foreach ($entities as $key => $entity) {
      if (!$entity
        ->isRecommended()) {
        unset($entities[$key]);
      }
    }
    return $entities;
  }

  /**
   * Get all not recommended entities.
   *
   * @return array
   *   An array of all not recommended entities.
   *
   * @throws \Drupal\search_api\SearchApiException
   */
  public function getNotRecommendedEntities() : array {
    $entities = $this
      ->load();
    foreach ($entities as $key => $entity) {
      if ($entity
        ->isRecommended()) {
        unset($entities[$key]);
      }
    }
    return $entities;
  }

  /**
   * Get all recommended entities.
   *
   * @return array
   *   An array of all recommended entities.
   */
  public function getAllRecommendedEntities() : array {

    // Bypass AbstractSolrEntityListBuilder::load() by calling the parent. But
    // don't use parent::load() in case someone copies this function in an
    // inherited class.
    $entities = ConfigEntityListBuilder::load();
    foreach ($entities as $key => $entity) {
      if (!$entity
        ->isRecommended()) {
        unset($entities[$key]);
      }
    }
    return $entities;
  }

  /**
   * Get all not recommended entities.
   *
   * @return array
   *   An array of all not recommended entities.
   */
  public function getAllNotRecommendedEntities() : array {

    // Bypass AbstractSolrEntityListBuilder::load() by calling the parent. But
    // don't use parent::load() in case someone copies this function in an
    // inherited class.
    $entities = ConfigEntityListBuilder::load();
    foreach ($entities as $key => $entity) {
      if ($entity
        ->isRecommended()) {
        unset($entities[$key]);
      }
    }
    return $entities;
  }

  /**
   * Get all conflicting entities.
   *
   * @return array
   *   An array of all conflicting entities.
   */
  public function getConflictingEntities(array $entities) : array {
    $conflicting_entities = [];
    $purpose_ids = [];
    foreach ($entities as $key => $entity) {
      $purpose_id = $entity
        ->getPurposeId();
      if (!in_array($purpose_id, $purpose_ids)) {
        $purpose_ids[] = $purpose_id;
      }
      else {
        $conflicting_entities[$key] = $entity;
      }
    }
    return $conflicting_entities;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AbstractSolrEntityListBuilder::$default_option protected property The default option.
AbstractSolrEntityListBuilder::$label protected property The label. 3
AbstractSolrEntityListBuilder::$limit protected property The number of entities to list per page, or FALSE to list all entities. Overrides EntityListBuilder::$limit
AbstractSolrEntityListBuilder::$option_label protected property The option label.
AbstractSolrEntityListBuilder::buildHeader public function Builds the header row for the entity listing. Overrides EntityListBuilder::buildHeader 1
AbstractSolrEntityListBuilder::buildRow public function Builds a row for an entity in the entity listing. Overrides EntityListBuilder::buildRow 1
AbstractSolrEntityListBuilder::getAllNotRecommendedEntities public function Get all not recommended entities.
AbstractSolrEntityListBuilder::getAllRecommendedEntities public function Get all recommended entities.
AbstractSolrEntityListBuilder::getConflictingEntities public function Get all conflicting entities.
AbstractSolrEntityListBuilder::getDefaultOperations public function Overrides ConfigEntityListBuilder::getDefaultOperations
AbstractSolrEntityListBuilder::getDisabledEntities abstract protected function Get all disabled entities. 4
AbstractSolrEntityListBuilder::getEnabledEntities public function Returns a list of all enabled Solr config entities for current server.
AbstractSolrEntityListBuilder::getNotRecommendedEntities public function Get all not recommended entities.
AbstractSolrEntityListBuilder::getRecommendedEntities public function Get all recommended Entities.
AbstractSolrEntityListBuilder::getXml public function Returns the formatted XML for the entities.
AbstractSolrEntityListBuilder::load public function Overrides ConfigEntityListBuilder::load 1
AbstractSolrEntityListBuilder::mergeSolrConfigs protected function Merge two Solr config entities.
BackendTrait::$assumedMinimumVersion protected property The Solr minimum version string.
BackendTrait::$backend protected property The Search API server backend.
BackendTrait::$reset protected property Reset.
BackendTrait::$serverId protected property The Search API server ID.
BackendTrait::getBackend protected function Returns the Search API server backend.
BackendTrait::setAssumedMinimumVersion public function Set assumed minimum version.
BackendTrait::setBackend public function Sets the Search API server backend.
BackendTrait::setServer public function Sets the Search API server and calls setBackend() afterwards.
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 1
DependencySerializationTrait::__wakeup public function 2
EntityHandlerBase::$moduleHandler protected property The module handler to invoke hooks on. 2
EntityHandlerBase::moduleHandler protected function Gets the module handler. 2
EntityHandlerBase::setModuleHandler public function Sets the module handler for this handler.
EntityListBuilder::$entityType protected property Information about the entity type.
EntityListBuilder::$entityTypeId protected property The entity type ID.
EntityListBuilder::$storage protected property The entity storage class. 1
EntityListBuilder::buildOperations public function Builds a renderable list of operation links for the entity. 2
EntityListBuilder::createInstance public static function Instantiates a new instance of this entity handler. Overrides EntityHandlerInterface::createInstance 20
EntityListBuilder::ensureDestination protected function Ensures that a destination is present on the given URL.
EntityListBuilder::getEntityIds protected function Loads entity IDs using a pager sorted by the entity id. 4
EntityListBuilder::getLabel Deprecated protected function Gets the label of an entity.
EntityListBuilder::getOperations public function Provides an array of information to build a list of operation links. Overrides EntityListBuilderInterface::getOperations 2
EntityListBuilder::getStorage public function Gets the entity storage. Overrides EntityListBuilderInterface::getStorage
EntityListBuilder::getTitle protected function Gets the title of the page. 1
EntityListBuilder::render public function Builds the entity listing as renderable array for table.html.twig. Overrides EntityListBuilderInterface::render 16
EntityListBuilder::__construct public function Constructs a new EntityListBuilder object. 16
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.