예제 #1
0
 /**
  * {@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;
 }
예제 #2
0
 /**
  * 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);
         }
     }
 }
예제 #3
0
 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;
 }