/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, ServerInterface $search_api_server = NULL) { $form['#title'] = $this->t('List of configuration files found'); try { // Retrieve the list of available files. $files_list = SearchApiSolrUtility::getServerFiles($search_api_server); if (empty($files_list)) { $form['info']['#markup'] = $this->t('No files found.'); return $form; } $form['files_tabs'] = array('#type' => 'vertical_tabs'); // Generate a fieldset for each file. foreach ($files_list as $file_name => $file_info) { $file_date = format_date(strtotime($file_info['modified'])); $escaped_file_name = SafeMarkup::checkPlain($file_name); $form['files'][$file_name] = array('#type' => 'details', '#title' => $escaped_file_name, '#group' => 'files_tabs'); $data = '<h3>' . $escaped_file_name . '</h3>'; $data .= '<p><em>' . $this->t('Last modified: @time.', array('@time' => $file_date)) . '</em></p>'; if ($file_info['size'] > 0) { $file_data = $search_api_server->getBackend()->getFile($file_name); $data .= '<pre><code>' . SafeMarkup::checkPlain($file_data->getBody()) . '</code></pre>'; } else { $data .= '<p><em>' . $this->t('The file is empty.') . '</em></p>'; } $form['files'][$file_name]['data']['#markup'] = $data; } } catch (SearchApiException $e) { watchdog_exception('search_api_solr', $e, '%type while retrieving config files of Solr server @server: !message in %function (line %line of %file).', array('@server' => $search_api_server->label())); $form['info']['#markup'] = $this->t('An error occured while trying to load the list of files.'); } return $form; }
/** * Adds spatial features to the search query. */ public function setSpatial(Query $solarium_query, QueryInterface $query, $spatial_options = array(), $field_names) { foreach ($spatial_options as $i => $spatial) { // reset radius for each option unset($radius); if (empty($spatial['field']) || empty($spatial['lat']) || empty($spatial['lon'])) { continue; } $field = $field_names[$spatial['field']]; $escaped_field = SearchApiSolrUtility::escapeFieldName($field); $point = (double) $spatial['lat'] . ',' . (double) $spatial['lon']; // Prepare the filter settings. if (isset($spatial['radius'])) { $radius = (double) $spatial['radius']; } $spatial_method = 'geofilt'; if (isset($spatial['method']) && in_array($spatial['method'], array('geofilt', 'bbox'))) { $spatial_method = $spatial['method']; } $filter_queries = $solarium_query->getFilterQueries(); // Change the fq facet ranges to the correct fq. foreach ($filter_queries as $key => $filter_query) { // If the fq consists only of a filter on this field, replace it with // a range. $preg_field = preg_quote($escaped_field, '/'); if (preg_match('/^' . $preg_field . ':\\["?(\\*|\\d+(?:\\.\\d+)?)"? TO "?(\\*|\\d+(?:\\.\\d+)?)"?\\]$/', $filter_query, $matches)) { unset($filter_queries[$key]); if ($matches[1] && is_numeric($matches[1])) { $min_radius = isset($min_radius) ? max($min_radius, $matches[1]) : $matches[1]; } if (is_numeric($matches[2])) { // Make the radius tighter accordingly. $radius = isset($radius) ? min($radius, $matches[2]) : $matches[2]; } } } // If either a radius was given in the option, or a filter was // encountered, set a filter for the lowest value. If a lower boundary // was set (too), we can only set a filter for that if the field name // doesn't contains any colons. if (isset($min_radius) && strpos($field, ':') === FALSE) { $upper = isset($radius) ? " u={$radius}" : ''; $solarium_query->createFilterQuery($field)->setQuery("{!frange l={$min_radius}{$upper}}geodist({$field},{$point})"); } elseif (isset($radius)) { $solarium_query->createFilterQuery($field)->setQuery("{!{$spatial_method} pt={$point} sfield={$field} d={$radius}}"); } // @todo: Check if this object returns the correct value $sorts = $solarium_query->getSorts(); // Change sort on the field, if set (and not already changed). if (isset($sorts[$spatial['field']]) && substr($sorts[$spatial['field']], 0, strlen($field)) === $field) { $sorts[$spatial['field']] = str_replace($field, "geodist({$field},{$point})", $sorts[$spatial['field']]); } // Change the facet parameters for spatial fields to return distance // facets. $facets = $solarium_query->getFacetSet(); // @todo: Fix this so it takes it from the solarium query if (!empty($facets)) { if (!empty($facet_params['facet.field'])) { $facet_params['facet.field'] = array_diff($facet_params['facet.field'], array($field)); } foreach ($facets as $delta => $facet) { if ($facet['field'] != $spatial['field']) { continue; } $steps = $facet['limit'] > 0 ? $facet['limit'] : 5; $step = (isset($radius) ? $radius : 100) / $steps; for ($k = $steps - 1; $k > 0; --$k) { $distance = $step * $k; $key = "spatial-{$delta}-{$distance}"; $facet_params['facet.query'][] = "{!{$spatial_method} pt={$point} sfield={$field} d={$distance} key={$key}}"; } foreach (array('limit', 'mincount', 'missing') as $setting) { unset($facet_params["f.{$field}.facet.{$setting}"]); } } } } // Normal sorting on location fields isn't possible. foreach (array_keys($solarium_query->getSorts()) as $sort) { if (substr($sort, 0, 3) === 'loc') { $solarium_query->removeSort($sort); } } }
public function getAutocompleteSuggestions(QueryInterface $query, SearchApiAutocompleteSearch $search, $incomplete_key, $user_input) { $suggestions = array(); // Reset request handler $this->request_handler = NULL; // Turn inputs to lower case, otherwise we get case sensivity problems. $incomp = Unicode::strtolower($incomplete_key); $index = $query->getIndex(); $field_names = $this->getFieldNames($index); $complete = $query->getOriginalKeys(); // Extract keys $keys = $query->getKeys(); if (is_array($keys)) { $keys_array = array(); while ($keys) { reset($keys); if (!element_child(key($keys))) { array_shift($keys); continue; } $key = array_shift($keys); if (is_array($key)) { $keys = array_merge($keys, $key); } else { $keys_array[$key] = $key; } } $keys = $this->getSolrHelper()->flattenKeys($query->getKeys()); } else { $keys_array = preg_split('/[-\\s():{}\\[\\]\\\\"]+/', $keys, -1, PREG_SPLIT_NO_EMPTY); $keys_array = array_combine($keys_array, $keys_array); } if (!$keys) { $keys = NULL; } // Set searched fields $options = $query->getOptions(); $search_fields = $query->getFulltextFields(); $qf = array(); foreach ($search_fields as $f) { $qf[] = $field_names[$f]; } // Extract filters $fq = $this->createFilterQueries($query->getFilter(), $field_names, $index->getOption('fields', array())); $index_id = $this->getIndexId($index->id()); $fq[] = 'index_id:' . $this->getQueryHelper()->escapePhrase($index_id); if ($this->configuration['site_hash']) { $site_hash = $this->getQueryHelper()->escapePhrase(SearchApiSolrUtility::getSiteHash()); $fq[] = 'hash:' . $site_hash; } // Autocomplete magic $facet_fields = array(); foreach ($search_fields as $f) { $facet_fields[] = $field_names[$f]; } $limit = $query->getOption('limit', 10); $params = array('qf' => $qf, 'fq' => $fq, 'rows' => 0, 'facet' => 'true', 'facet.field' => $facet_fields, 'facet.prefix' => $incomp, 'facet.limit' => $limit * 5, 'facet.mincount' => 1, 'spellcheck' => !isset($this->configuration['autocorrect_spell']) || $this->configuration['autocorrect_spell'] ? 'true' : 'false', 'spellcheck.count' => 1); // Retrieve http method from server options. $http_method = !empty($this->configuration['http_method']) ? $this->configuration['http_method'] : 'AUTO'; $call_args = array('query' => &$keys, 'params' => &$params, 'http_method' => &$http_method); if ($this->request_handler) { $this->setRequestHandler($this->request_handler, $call_args); } $second_pass = !isset($this->configuration['autocorrect_suggest_words']) || $this->configuration['autocorrect_suggest_words']; for ($i = 0; $i < ($second_pass ? 2 : 1); ++$i) { try { // Send search request $this->connect(); $this->moduleHandler->alter('search_api_solr_query', $call_args, $query); $this->preQuery($call_args, $query); $response = $this->solr->search($keys, $params, $http_method); if (!empty($response->spellcheck->suggestions)) { $replace = array(); foreach ($response->spellcheck->suggestions as $word => $data) { $replace[$word] = $data->suggestion[0]; } $corrected = str_ireplace(array_keys($replace), array_values($replace), $user_input); if ($corrected != $user_input) { array_unshift($suggestions, array('prefix' => $this->t('Did you mean') . ':', 'user_input' => $corrected)); } } $matches = array(); if (isset($response->facet_counts->facet_fields)) { foreach ($response->facet_counts->facet_fields as $terms) { foreach ($terms as $term => $count) { if (isset($matches[$term])) { // If we just add the result counts, we can easily get over the // total number of results if terms appear in multiple fields. // Therefore, we just take the highest value from any field. $matches[$term] = max($matches[$term], $count); } else { $matches[$term] = $count; } } } if ($matches) { // Eliminate suggestions that are too short or already in the query. foreach ($matches as $term => $count) { if (strlen($term) < 3 || isset($keys_array[$term])) { unset($matches[$term]); } } // Don't suggest terms that are too frequent (by default in more // than 90% of results). $result_count = $response->response->numFound; $max_occurrences = $result_count * $this->searchApiSolrSettings->get('autocomplete_max_occurrences'); if (($max_occurrences >= 1 || $i > 0) && $max_occurrences < $result_count) { foreach ($matches as $match => $count) { if ($count > $max_occurrences) { unset($matches[$match]); } } } // The $count in this array is actually a score. We want the // highest ones first. arsort($matches); // Shorten the array to the right ones. $additional_matches = array_slice($matches, $limit - count($suggestions), NULL, TRUE); $matches = array_slice($matches, 0, $limit, TRUE); // Build suggestions using returned facets $incomp_length = strlen($incomp); foreach ($matches as $term => $count) { if (Unicode::strtolower(substr($term, 0, $incomp_length)) == $incomp) { $suggestions[] = array('suggestion_suffix' => substr($term, $incomp_length), 'term' => $term, 'results' => $count); } else { $suggestions[] = array('suggestion_suffix' => ' ' . $term, 'term' => $term, 'results' => $count); } } } } } catch (SearchApiException $e) { watchdog_exception('search_api_solr', $e, "%type during autocomplete Solr query: !message in %function (line %line of %file).", array(), WATCHDOG_WARNING); } if (count($suggestions) >= $limit) { break; } // Change parameters for second query. unset($params['facet.prefix']); $keys = trim($keys . ' ' . $incomplete_key); } return $suggestions; }