You are here

protected function SearchApiSolrBackend::formatSolrFieldNames in Search API Solr 8.3

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

Returns a language-specific mapping from Drupal to Solr field names.

Parameters

string $language_id: The language to get the mapping for.

\Drupal\search_api\IndexInterface $index: The Search API index entity.

Return value

array The language-specific mapping from Drupal to Solr field names.

Throws

\Drupal\search_api\SearchApiException

1 call to SearchApiSolrBackend::formatSolrFieldNames()
SearchApiSolrBackend::getLanguageSpecificSolrFieldNames in src/Plugin/search_api/backend/SearchApiSolrBackend.php
Gets a language-specific mapping from Drupal to Solr field names.

File

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

Class

SearchApiSolrBackend
Apache Solr backend for search api.

Namespace

Drupal\search_api_solr\Plugin\search_api\backend

Code

protected function formatSolrFieldNames($language_id, IndexInterface $index) {

  // Caching is done by getLanguageSpecificSolrFieldNames().
  // This array maps "local property name" => "solr doc property name".
  $field_mapping = [
    'search_api_relevance' => 'score',
    'search_api_random' => 'random',
    'boost_document' => 'boost_document',
  ];

  // Add the names of any fields configured on the index.
  $fields = $index
    ->getFields();
  $fields += $this
    ->getSpecialFields($index);
  foreach ($fields as $search_api_name => $field) {
    switch ($field
      ->getDatasourceId()) {
      case 'solr_document':
        $field_mapping[$search_api_name] = $field
          ->getPropertyPath();
        break;
      case 'solr_multisite_document':
        $field_mapping[$search_api_name] = Utility::encodeSolrName(preg_replace('/^(t[a-z0-9]*[ms]' . SolrBackendInterface::SEARCH_API_SOLR_LANGUAGE_SEPARATOR . ')' . LanguageInterface::LANGCODE_NOT_SPECIFIED . '(.+)/', '$1' . $language_id . '$2', Utility::decodeSolrName($field
          ->getPropertyPath())));
        break;
      default:
        if (empty($field_mapping[$search_api_name])) {

          // Generate a field name; this corresponds with naming conventions
          // in our schema.xml.
          $type = $field
            ->getType();
          if ('solr_text_suggester' === $type) {

            // Any field of this type will be indexed in the same Solr field.
            // The 'twm_suggest' is the backend for the suggester component.
            $field_mapping[$search_api_name] = 'twm_suggest';
            break;
          }
          if ('solr_text_spellcheck' === $type) {

            // Any field of this type will be indexed in the same Solr field.
            // Don't use the language separator here! This field name is used
            // without in in the solrconfig.xml.
            $field_mapping[$search_api_name] = 'spellcheck_' . $language_id;
            break;
          }
          $type_info = Utility::getDataTypeInfo($type);
          $pref = $type_info['prefix'] ?? '';
          if (strpos($pref, 't') === 0) {

            // All text types need to be treated as multiple because some
            // Search API processors produce boosted string tokens for
            // a single valued drupal field. We need to store such tokens and
            // their boost, too.
            // The dynamic field tm_* will become tm;en* for English.
            // Following this pattern we also have fall backs automatically:
            // - tm;de-AT_*
            // - tm;de_*
            // - tm_*
            // This concept bases on the fact that "longer patterns will be
            // matched first. If equal size patterns both match, the first
            // appearing in the schema will be used." This is not obvious from
            // the example above. But you need to take into account that the
            // real field name for solr will be encoded. So the real values
            // for the example above are:
            // - tm_X3b_de_X2d_AT_*
            // - tm_X3b_de_*
            // - tm_*
            // See also:
            // @see \Drupal\search_api_solr\Utility\Utility::encodeSolrName()
            // @see https://wiki.apache.org/solr/SchemaXml#Dynamic_fields
            $pref .= 'm' . SolrBackendInterface::SEARCH_API_SOLR_LANGUAGE_SEPARATOR . $language_id;
          }
          else {
            if ($this->fieldsHelper
              ->isFieldIdReserved($search_api_name)) {
              $pref .= 's';
            }
            else {
              if ($field
                ->getDataDefinition()
                ->isList() || $this
                ->isHierarchicalField($field)) {
                $pref .= 'm';
              }
              else {
                try {
                  $datasource = $field
                    ->getDatasource();
                  if (!$datasource) {
                    throw new SearchApiException();
                  }
                  $pref .= $this
                    ->getPropertyPathCardinality($field
                    ->getPropertyPath(), $datasource
                    ->getPropertyDefinitions()) != 1 ? 'm' : 's';
                } catch (SearchApiException $e) {

                  // Thrown by $field->getDatasource(). Assume multi value to
                  // be safe.
                  $pref .= 'm';
                }
              }
            }
          }
          $name = $pref . '_' . $search_api_name;
          $field_mapping[$search_api_name] = Utility::encodeSolrName($name);

          // Add a distance pseudo field for any location field. These fields
          // don't really exist in the solr core, but we tell solr to name the
          // distance calculation results that way. Later we directly pass
          // these as "fields" to Drupal and especially Views.
          if ($type === 'location') {

            // Solr returns the calculated distance value as a single decimal
            // value (even for multi-valued location fields). Therefore we
            // have to prefix the field name accordingly by fts_*.
            // This ensures that this field works as for sorting, too.
            // 'ft' is the prefix for decimal (at the moment).
            $dist_info = Utility::getDataTypeInfo('decimal');
            $field_mapping[$search_api_name . '__distance'] = Utility::encodeSolrName($dist_info['prefix'] . 's_' . $search_api_name . '__distance');
          }
        }
    }
  }
  if (Utility::hasIndexJustSolrDatasources($index)) {

    // No other datasource than solr_*, overwrite some search_api_* fields.
    $config = $this
      ->getDatasourceConfig($index);
    $field_mapping['search_api_id'] = $config['id_field'];
    $field_mapping['search_api_language'] = $config['language_field'];
  }

  // Let modules adjust the field mappings.
  $this->moduleHandler
    ->alter('search_api_solr_field_mapping', $index, $field_mapping, $language_id);
  return $field_mapping;
}