/** * Получить массив с заголовками страниц для autocomplete * @param string $input * @param string $language * @param integer $site_id * @return array элементы массива: array("label" => "Page Title", "url" => "/path/") */ public function suggest_titles($input, $language, $site_id) { $limit = nc_search::get_setting('NumberOfSuggestions'); $index_search_results = ""; $document_order_by_id = "1"; // поиск в индексе (то есть будут варианты после обработки фильтрами - базовая форма) if (nc_search::should('SearchTitleBaseformsForSuggestions')) { $last_space = strrpos($input, " "); $as_phrase = nc_search::should('SearchTitleAsPhraseForSuggestions'); $b1 = $as_phrase ? '"' : '('; $b2 = $as_phrase ? '"' : ')'; /* @todo сделать проверку на то, что последнее слово является правильным/полным? */ $query_string = "(title:{$b1}{$input}{$b2}" . ($last_space ? " OR title:{$b1}" . trim(substr($input, 0, $last_space)) . $b2 : '') . ")"; $query = new nc_search_query($query_string); $query->set('limit', $limit)->set('options_to_fetch', array('title', 'site_id', 'path'))->set('language', $language)->set('area', "site" . (int) $site_id); // some lower level magic $translator = new nc_search_provider_index_translator($this); $document_ids = $this->get_db()->get_col($query->translate($translator)); if ($document_ids) { $document_ids = join(", ", $document_ids); $index_search_results = "OR `Document_ID` IN ({$document_ids})\n"; $document_order_by_id = "FIELD(`Document_ID`, {$document_ids})"; } } // поиск точного соответствия в таблице с документами $like_expression = '`Title` LIKE "' . nc_search_util::db_escape($input) . '%" '; $query = "SELECT `Catalogue_ID`, `Path`, `Title` FROM `%t%`\n" . "WHERE {$like_expression}\n" . $index_search_results . "ORDER BY {$like_expression}, {$document_order_by_id}\n" . "LIMIT {$limit}"; $documents = new nc_search_result(); $documents->select_from_database($query); $suggestions = array(); // собственно подсказки /** @var $doc nc_search_document */ foreach ($documents as $doc) { $suggestions[] = array("label" => $doc->get('title'), "url" => $doc->get('url')); } return $suggestions; }
/** * * @param string $query_string * @param string|array $area * @param string $params Параметры, через амперсанд * - field - поле поиска. Допустимые значения: 'title' * - interval - непустое значение, если включена фильтрация по дате * - intervalvalue - значение интервала * - intervalunit - тип интервала (hour, day, week, month) * - sortby - сортировка. Если пустое значение - сортировка по релевантности. * Допустимые значения: last_updated или имя поля, по которому разрешена сортировка * - sortdirection - desc (по умолчанию), asc * - language - язык результатов, по умолчанию определяется автоматически * - curPos - текущая позиция (номер первого результата) * - recNum - количество результатов на странице, по умолчанию 10 (берется из * настроек компонента в разделе) * - correct - пытаться исправить запросы, не давшие результатов (по умолчанию * равно соответствующей настройки модуля) * - nologging - не записывать запрос в журнал запросов (при просмотре * результатов из админки, чтобы не искажать картину запросов) * @return nc_search_data_persistent_collection */ public function get_results($query_string, $area = "", $params = "") { if (!nc_search::should('EnableSearch')) { return new nc_search_result(); } // return empty collection $start_time = microtime(true); $query_string = (string) $query_string; global $nc_core; parse_str($params, $params); if (isset($params["field"]) && $params["field"] && nc_search::should('AllowFieldSearch')) { $query_string = "{$params['field']}:({$query_string})"; } $query = new nc_search_query($query_string); $has_interval = isset($params["interval"]) && isset($params["intervalvalue"]) && isset($params["intervalunit"]) && $params["interval"] && $params["intervalvalue"] && $params["intervalunit"]; if ($has_interval) { $timestamp = strtotime("-{$params['intervalvalue']} {$params['intervalunit']}"); $query->set('modified_after', strftime("%Y%m%d%H%M%S", $timestamp)); } $allow_sort = isset($params["sortby"]) && $params["sortby"] && nc_search::should('AllowFieldSearch'); if ($allow_sort) { $query->set('sort_by', $params["sortby"]); if (isset($params["sortdirection"]) && strtoupper($params["sortdirection"]) == 'ASC') { $query->set('sort_direction', SORT_ASC); } } if (isset($params["curPos"]) && $params["curPos"]) { $query->set('offset', (int) $params["curPos"]); } if (isset($params["recNum"]) && $params["recNum"]) { $query->set('limit', (int) $params["recNum"]); } if ($area) { if (is_array($area)) { $area = join(" ", $area); } $query->set('area', $area); } $language = isset($params["language"]) && $params["language"] ? $params["language"] : $nc_core->lang->detect_lang(1); $query->set('language', $language); $shutdown_page_path = nc_folder_path($nc_core->subdivision->get_current('Subdivision_ID')); register_shutdown_function('nc_search_shutdown', $shutdown_page_path, $query_string); $query_error = false; try { $results = nc_search::find($query); } catch (Exception $e) { $query_error = true; $results = new nc_search_result(); $results->set_query($query)->set_error_message($e->getMessage()); } $results->set_output_encoding(nc_core('NC_CHARSET')); // попробуем исправить, если не было результатов? $try_to_correct = $results->get_total_count() == 0 && !$query_error && (isset($params["correct"]) && $params["correct"] || nc_search::should('TryToCorrectQueries')) && preg_match_all('/[\\pL\\pN\\?\\*]+/u', $query_string, $tmp) <= nc_search::get_setting('MaxQueryLengthForCorrection'); if ($try_to_correct) { $context = new nc_search_context(array("language" => $language, "action" => "searching")); $correctors = nc_search_extension_manager::get('nc_search_language_corrector', $context)->get_all(); if (sizeof($correctors)) { $phrase = new nc_search_language_corrector_phrase($query_string); $rewritten_query = clone $query; foreach ($correctors as $corrector) { if ($corrector->correct($phrase)) { // что-то подправили // попробуем поискать! $rewritten_query->set('query_string', $phrase->to_string()); try { $corrected_results = nc_search::find($rewritten_query); if (sizeof($corrected_results)) { $results = $corrected_results; $results->set_correction_suggestion($phrase->get_suggestion()); $results->set_output_encoding(nc_core('NC_CHARSET')); break; // exit "foreach corrector" } } catch (Exception $e) { // может упасть, например, если у изменённого слова есть несколько базовых форм... } } // of "something changed" } // of "foreach corrector" } // end of "has correctors" } // end of "if ($try_to_correct)" $will_log = true; if (isset($params['nologging']) && $params['nologging'] && strlen($query_string)) { // только очень крутым чувакам разрешается не оставлять следов if (isset($GLOBALS['AUTH_USER_ID']) && isset($GLOBALS['perm']) && $GLOBALS["perm"]->isAccess(NC_PERM_MODULE)) { $will_log = false; } } if ($will_log && nc_search::should('SaveQueryHistory') && $query->get('offset') == 0) { $ip = ip2long($_SERVER['REMOTE_ADDR']); // achtung! не будет работать с IPv6! if ($ip > 0x7fffffff) { $ip -= 0x100000000; } // produce a signed 4-byte integer on 64-bit systems $query->set('results_count', $results->get_total_count())->set('user_ip', $ip)->set('user_id', $GLOBALS['AUTH_USER_ID'])->set('site_id', $GLOBALS['catalogue'])->save(); } $results->set_search_time(microtime(true) - $start_time); return $results; }
/** * @param string $input * @param string $language * @param integer $site_id * @return array */ public function suggest_titles($input, $language, $site_id) { $suggestions = array(); // собственно подсказки $titles = array(); $limit = nc_search::get_setting('NumberOfSuggestions'); // поиск в индексе (то есть будут варианты после обработки фильтрами - базовая форма) if (nc_search::should('SearchTitleBaseformsForSuggestions')) { $last_space = strrpos($input, " "); $as_phrase = nc_search::should('SearchTitleAsPhraseForSuggestions'); $b1 = $as_phrase ? '"' : '('; $b2 = $as_phrase ? '"' : ')'; /* @todo сделать проверку на то, что последнее слово является правильным/полным? */ $query_string = "(title:{$b1}{$input}{$b2}" . ($last_space ? " OR title:{$b1}" . trim(substr($input, 0, $last_space)) . $b2 : '') . ") AND site_id:{$site_id}"; $query = new nc_search_query($query_string); $query->set('limit', $limit)->set('options_to_fetch', array('title', 'site_id', 'path'))->set('language', $language); $documents = $this->find($query, false); foreach ($documents as $doc) { $suggestions[] = array("label" => $doc->get('title'), "url" => $doc->get('url')); $titles[] = '"' . nc_search_util::db_escape($doc->get('title')) . '"'; } $titles = array_unique($titles); } // поиск точного соответствия в таблице с документами // по-хорошему следовало бы сначала сделать запрос к БД, а потом к индексу, однако // в случае запроса к индексу не получится так же просто отфильтровать уже совпавшие запросы $query = "SELECT `Catalogue_ID`, `Path`, `Title` FROM `%t%` " . ' WHERE `Title` LIKE "' . nc_search_util::db_escape($input) . '%" ' . ($titles ? " AND `Title` NOT IN (" . join(", ", $titles) . ") " : "") . " ORDER BY `Title` " . " LIMIT {$limit}"; $documents = new nc_search_result(); $documents->select_from_database($query); foreach ($documents as $doc) { array_unshift($suggestions, array("label" => $doc->get('title'), "url" => $doc->get('url'))); } $suggestions = array_slice($suggestions, 0, $limit); return $suggestions; }