/** * @param ApiPageSet $resultPageSet * @return void */ private function run($resultPageSet = null) { global $wgContLang; $params = $this->extractRequestParams(); // Extract parameters $limit = $params['limit']; $query = $params['search']; $what = $params['what']; $interwiki = $params['interwiki']; $searchInfo = array_flip($params['info']); $prop = array_flip($params['prop']); // Deprecated parameters if (isset($prop['hasrelated'])) { $this->logFeatureUsage('action=search&srprop=hasrelated'); $this->setWarning('srprop=hasrelated has been deprecated'); } if (isset($prop['score'])) { $this->logFeatureUsage('action=search&srprop=score'); $this->setWarning('srprop=score has been deprecated'); } // Create search engine instance and set options $search = isset($params['backend']) && $params['backend'] != self::BACKEND_NULL_PARAM ? SearchEngine::create($params['backend']) : SearchEngine::create(); $search->setLimitOffset($limit + 1, $params['offset']); $search->setNamespaces($params['namespace']); $search->setFeatureData('rewrite', (bool) $params['enablerewrites']); $query = $search->transformSearchTerm($query); $query = $search->replacePrefixes($query); // Perform the actual search if ($what == 'text') { $matches = $search->searchText($query); } elseif ($what == 'title') { $matches = $search->searchTitle($query); } elseif ($what == 'nearmatch') { // near matches must receive the user input as provided, otherwise // the near matches within namespaces are lost. $matches = SearchEngine::getNearMatchResultSet($params['search']); } else { // We default to title searches; this is a terrible legacy // of the way we initially set up the MySQL fulltext-based // search engine with separate title and text fields. // In the future, the default should be for a combined index. $what = 'title'; $matches = $search->searchTitle($query); // Not all search engines support a separate title search, // for instance the Lucene-based engine we use on Wikipedia. // In this case, fall back to full-text search (which will // include titles in it!) if (is_null($matches)) { $what = 'text'; $matches = $search->searchText($query); } } if (is_null($matches)) { $this->dieUsage("{$what} search is disabled", "search-{$what}-disabled"); } elseif ($matches instanceof Status && !$matches->isGood()) { $this->dieUsage($matches->getWikiText(), 'search-error'); } if ($resultPageSet === null) { $apiResult = $this->getResult(); // Add search meta data to result if (isset($searchInfo['totalhits'])) { $totalhits = $matches->getTotalHits(); if ($totalhits !== null) { $apiResult->addValue(array('query', 'searchinfo'), 'totalhits', $totalhits); } } if (isset($searchInfo['suggestion']) && $matches->hasSuggestion()) { $apiResult->addValue(array('query', 'searchinfo'), 'suggestion', $matches->getSuggestionQuery()); $apiResult->addValue(array('query', 'searchinfo'), 'suggestionsnippet', $matches->getSuggestionSnippet()); } if (isset($searchInfo['rewrittenquery']) && $matches->hasRewrittenQuery()) { $apiResult->addValue(array('query', 'searchinfo'), 'rewrittenquery', $matches->getQueryAfterRewrite()); $apiResult->addValue(array('query', 'searchinfo'), 'rewrittenquerysnippet', $matches->getQueryAfterRewriteSnippet()); } } // Add the search results to the result $terms = $wgContLang->convertForSearchResult($matches->termMatches()); $titles = array(); $count = 0; $result = $matches->next(); while ($result) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional items to be had. Stop here... $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); break; } // Silently skip broken and missing titles if ($result->isBrokenTitle() || $result->isMissingRevision()) { $result = $matches->next(); continue; } $title = $result->getTitle(); if ($resultPageSet === null) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); if (isset($prop['snippet'])) { $vals['snippet'] = $result->getTextSnippet($terms); } if (isset($prop['size'])) { $vals['size'] = $result->getByteSize(); } if (isset($prop['wordcount'])) { $vals['wordcount'] = $result->getWordCount(); } if (isset($prop['timestamp'])) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $result->getTimestamp()); } if (isset($prop['titlesnippet'])) { $vals['titlesnippet'] = $result->getTitleSnippet(); } if (isset($prop['categorysnippet'])) { $vals['categorysnippet'] = $result->getCategorySnippet(); } if (!is_null($result->getRedirectTitle())) { if (isset($prop['redirecttitle'])) { $vals['redirecttitle'] = $result->getRedirectTitle()->getPrefixedText(); } if (isset($prop['redirectsnippet'])) { $vals['redirectsnippet'] = $result->getRedirectSnippet(); } } if (!is_null($result->getSectionTitle())) { if (isset($prop['sectiontitle'])) { $vals['sectiontitle'] = $result->getSectionTitle()->getFragment(); } if (isset($prop['sectionsnippet'])) { $vals['sectionsnippet'] = $result->getSectionSnippet(); } } if (isset($prop['isfilematch'])) { $vals['isfilematch'] = $result->isFileMatch(); } // Add item to results and see whether it fits $fit = $apiResult->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('offset', $params['offset'] + $count - 1); break; } } else { $titles[] = $title; } $result = $matches->next(); } $hasInterwikiResults = false; $totalhits = null; if ($interwiki && $resultPageSet === null && $matches->hasInterwikiResults()) { foreach ($matches->getInterwikiResults() as $matches) { $matches = $matches->getInterwikiResults(); $hasInterwikiResults = true; // Include number of results if requested if ($resultPageSet === null && isset($searchInfo['totalhits'])) { $totalhits += $matches->getTotalHits(); } $result = $matches->next(); while ($result) { $title = $result->getTitle(); if ($resultPageSet === null) { $vals = array('namespace' => $result->getInterwikiNamespaceText(), 'title' => $title->getText(), 'url' => $title->getFullUrl()); // Add item to results and see whether it fits $fit = $apiResult->addValue(array('query', 'interwiki' . $this->getModuleName(), $result->getInterwikiPrefix()), null, $vals); if (!$fit) { // We hit the limit. We can't really provide any meaningful // pagination info so just bail out break; } } else { $titles[] = $title; } $result = $matches->next(); } } if ($totalhits !== null) { $apiResult->addValue(array('query', 'interwikisearchinfo'), 'totalhits', $totalhits); } } if ($resultPageSet === null) { $apiResult->addIndexedTagName(array('query', $this->getModuleName()), 'p'); if ($hasInterwikiResults) { $apiResult->addIndexedTagName(array('query', 'interwiki' . $this->getModuleName()), 'p'); } } else { $resultPageSet->populateFromTitles($titles); $offset = $params['offset'] + 1; foreach ($titles as $index => $title) { $resultPageSet->setGeneratorData($title, array('index' => $index + $offset)); } } }
/** * @param $resultPageSet ApiPageSet * @return void */ private function run($resultPageSet = null) { global $wgContLang; $params = $this->extractRequestParams(); // Extract parameters $limit = $params['limit']; $query = $params['search']; $what = $params['what']; $searchInfo = array_flip($params['info']); $prop = array_flip($params['prop']); // Create search engine instance and set options $search = isset($params['backend']) && $params['backend'] != self::BACKEND_NULL_PARAM ? SearchEngine::create($params['backend']) : SearchEngine::create(); $search->setLimitOffset($limit + 1, $params['offset']); $search->setNamespaces($params['namespace']); $search->showRedirects = $params['redirects']; $query = $search->transformSearchTerm($query); $query = $search->replacePrefixes($query); // Perform the actual search if ($what == 'text') { $matches = $search->searchText($query); } elseif ($what == 'title') { $matches = $search->searchTitle($query); } elseif ($what == 'nearmatch') { $matches = SearchEngine::getNearMatchResultSet($query); } else { // We default to title searches; this is a terrible legacy // of the way we initially set up the MySQL fulltext-based // search engine with separate title and text fields. // In the future, the default should be for a combined index. $what = 'title'; $matches = $search->searchTitle($query); // Not all search engines support a separate title search, // for instance the Lucene-based engine we use on Wikipedia. // In this case, fall back to full-text search (which will // include titles in it!) if (is_null($matches)) { $what = 'text'; $matches = $search->searchText($query); } } if (is_null($matches)) { $this->dieUsage("{$what} search is disabled", "search-{$what}-disabled"); } elseif ($matches instanceof Status && !$matches->isGood()) { $this->dieUsage($matches->getWikiText(), 'search-error'); } $apiResult = $this->getResult(); // Add search meta data to result if (isset($searchInfo['totalhits'])) { $totalhits = $matches->getTotalHits(); if ($totalhits !== null) { $apiResult->addValue(array('query', 'searchinfo'), 'totalhits', $totalhits); } } if (isset($searchInfo['suggestion']) && $matches->hasSuggestion()) { $apiResult->addValue(array('query', 'searchinfo'), 'suggestion', $matches->getSuggestionQuery()); } // Add the search results to the result $terms = $wgContLang->convertForSearchResult($matches->termMatches()); $titles = array(); $count = 0; $result = $matches->next(); while ($result) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional items to be had. Stop here... $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); break; } // Silently skip broken and missing titles if ($result->isBrokenTitle() || $result->isMissingRevision()) { $result = $matches->next(); continue; } $title = $result->getTitle(); if (is_null($resultPageSet)) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); if (isset($prop['snippet'])) { $vals['snippet'] = $result->getTextSnippet($terms); } if (isset($prop['size'])) { $vals['size'] = $result->getByteSize(); } if (isset($prop['wordcount'])) { $vals['wordcount'] = $result->getWordCount(); } if (isset($prop['timestamp'])) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $result->getTimestamp()); } if (!is_null($result->getScore()) && isset($prop['score'])) { $vals['score'] = $result->getScore(); } if (isset($prop['titlesnippet'])) { $vals['titlesnippet'] = $result->getTitleSnippet($terms); } if (!is_null($result->getRedirectTitle())) { if (isset($prop['redirecttitle'])) { $vals['redirecttitle'] = $result->getRedirectTitle(); } if (isset($prop['redirectsnippet'])) { $vals['redirectsnippet'] = $result->getRedirectSnippet($terms); } } if (!is_null($result->getSectionTitle())) { if (isset($prop['sectiontitle'])) { $vals['sectiontitle'] = $result->getSectionTitle()->getFragment(); } if (isset($prop['sectionsnippet'])) { $vals['sectionsnippet'] = $result->getSectionSnippet(); } } if (isset($prop['hasrelated']) && $result->hasRelated()) { $vals['hasrelated'] = ''; } // Add item to results and see whether it fits $fit = $apiResult->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('offset', $params['offset'] + $count - 1); break; } } else { $titles[] = $title; } $result = $matches->next(); } if (is_null($resultPageSet)) { $apiResult->setIndexedTagName_internal(array('query', $this->getModuleName()), 'p'); } else { $resultPageSet->populateFromTitles($titles); } }