You are here

public function SearchApiSolrBackend::getDocuments in Search API Solr 8.3

Same name and namespace in other branches
  1. 8 src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::getDocuments()
  2. 8.2 src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::getDocuments()
  3. 4.x src/Plugin/search_api/backend/SearchApiSolrBackend.php \Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend::getDocuments()

Throws

\Drupal\Component\Plugin\Exception\PluginException

Overrides SolrBackendInterface::getDocuments

2 calls to SearchApiSolrBackend::getDocuments()
SearchApiSolrBackend::getDocument in src/Plugin/search_api/backend/SearchApiSolrBackend.php
SearchApiSolrBackend::indexItems in src/Plugin/search_api/backend/SearchApiSolrBackend.php

File

src/Plugin/search_api/backend/SearchApiSolrBackend.php, line 1020

Class

SearchApiSolrBackend
Apache Solr backend for search api.

Namespace

Drupal\search_api_solr\Plugin\search_api\backend

Code

public function getDocuments(IndexInterface $index, array $items, UpdateQuery $update_query = NULL) {
  $documents = [];
  $index_id = $this
    ->getTargetedIndexId($index);
  $site_hash = $this
    ->getTargetedSiteHash($index);
  $languages = $this->languageManager
    ->getLanguages();
  $request_time = $this
    ->formatDate(\Drupal::time()
    ->getRequestTime());
  $base_urls = [];
  if (!$update_query) {
    $connector = $this
      ->getSolrConnector();
    $update_query = $connector
      ->getUpdateQuery();
  }

  /** @var \Drupal\search_api\Item\ItemInterface[] $items */
  foreach ($items as $id => $item) {
    $language_id = $item
      ->getLanguage();
    $field_names = $this
      ->getLanguageSpecificSolrFieldNames($language_id, $index);

    /** @var \Solarium\QueryType\Update\Query\Document $doc */
    $doc = $update_query
      ->createDocument();
    $doc
      ->setField('timestamp', $request_time);
    $doc
      ->setField('id', $this
      ->createId($site_hash, $index_id, $id));
    $doc
      ->setField('index_id', $index_id);

    // Some processors might add an absolute boost factor to the item. Since
    // Solr doesn't support index time boosting anymore, we simply store that
    // factor and include it in the boost calculation at query time.
    // @see \Drupal\search_api\Plugin\search_api\processor\TypeBoost
    $doc
      ->setField('boost_document', $item
      ->getBoost());

    // Suggester context boolean filter queries have issues with special
    // characters like '/' or ':' if not properly quoted (by solarium). We
    // avoid that by reusing our field name encoding.
    $doc
      ->addField('sm_context_tags', Utility::encodeSolrName('search_api/index:' . $index_id));

    // Add the site hash and language-specific base URL.
    $doc
      ->setField('hash', $site_hash);
    $doc
      ->addField('sm_context_tags', Utility::encodeSolrName('search_api_solr/site_hash:' . $site_hash));
    $doc
      ->addField('sm_context_tags', Utility::encodeSolrName('drupal/langcode:' . $language_id));
    if (!isset($base_urls[$language_id])) {
      $url_options = [
        'absolute' => TRUE,
      ];
      if (isset($languages[$language_id])) {
        $url_options['language'] = $languages[$language_id];
      }

      // An exception is thrown if this is called during a non-HTML response
      // like REST or a redirect without collecting metadata. Avoid that by
      // collecting and discarding it.
      // See https://www.drupal.org/node/2638686.
      $base_urls[$language_id] = Url::fromRoute('<front>', [], $url_options)
        ->toString(TRUE)
        ->getGeneratedUrl();
    }
    $doc
      ->setField('site', $base_urls[$language_id]);
    $item_fields = $item
      ->getFields();
    $item_fields += $special_fields = $this
      ->getSpecialFields($index, $item);

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

      // If the field is not known for the index, something weird has
      // happened. We refuse to index the items and hope that the others are
      // OK.
      if (!isset($field_names[$name])) {
        $vars = [
          '%field' => $name,
          '@id' => $id,
        ];
        $this
          ->getLogger()
          ->warning('Error while indexing: Unknown field %field on the item with ID @id.', $vars);
        $doc = NULL;
        break;
      }
      $first_value = $this
        ->addIndexField($doc, $field_names[$name], $field
        ->getValues(), $field
        ->getType());

      // Enable sorts in some special cases.
      if ($first_value && !array_key_exists($name, $special_fields)) {
        if (strpos($field_names[$name], 't') === 0 && strpos($field_names[$name], 'twm_suggest') !== 0 || strpos($field_names[$name], 's') === 0 && strpos($field_names[$name], 'spellcheck') !== 0) {

          // Truncate the string to avoid Solr string field limitation.
          // @see https://www.drupal.org/node/2809429
          // @see https://www.drupal.org/node/2852606
          // 128 characters should be enough for sorting and it makes no
          // sense to heavily increase the index size. The DB backend limits
          // the sort strings to 32 characters. But for example a
          // search_api_id quickly exceeds 32 characters and the interesting
          // ID is at the end of the string:
          // 'entity:entity_test_mulrev_changed/2:en'.
          if (mb_strlen($first_value) > 128) {
            $first_value = Unicode::truncate($first_value, 128);
          }

          // Always copy fulltext and string fields to a dedicated sort fields
          // for faster sorts and language specific collations. To allow
          // sorted multilingual searches we need to fill *all*
          // language-specific sort fields!
          $sort_languages = array_keys(\Drupal::languageManager()
            ->getLanguages());
          $sort_languages[] = LanguageInterface::LANGCODE_NOT_SPECIFIED;
          foreach ($sort_languages as $sort_language_id) {
            $key = Utility::encodeSolrName('sort' . SolrBackendInterface::SEARCH_API_SOLR_LANGUAGE_SEPARATOR . $sort_language_id . '_' . $name);
            if (!$doc->{$key}) {
              $doc
                ->addField($key, $first_value);
            }
          }
        }
        elseif (preg_match('/^([a-z]+)m(_.*)/', $field_names[$name], $matches) && strpos($field_names[$name], 'random_') !== 0) {
          $key = $matches[1] . 's' . $matches[2];
          if (!$doc->{$key}) {

            // For other multi-valued fields (which aren't sortable by nature)
            // we use the same hackish workaround like the DB backend: just
            // copy the first value in a single value field for sorting.
            $doc
              ->addField($key, $first_value);
          }
        }
      }
    }
    if ($doc) {
      $documents[] = $doc;
    }
  }

  // Let other modules alter documents before sending them to solr.
  $this->moduleHandler
    ->alter('search_api_solr_documents', $documents, $index, $items);
  return $documents;
}