'IP' => __DIR__ . '/includes/libs/IP.php',
'IPTC' => __DIR__ . '/includes/media/IPTC.php',
'IRCColourfulRCFeedFormatter' => __DIR__ . '/includes/rcfeed/IRCColourfulRCFeedFormatter.php',
+ 'ISearchResultSet' => __DIR__ . '/includes/search/ISearchResultSet.php',
'IStoreKeyEncoder' => __DIR__ . '/includes/libs/objectcache/IStoreKeyEncoder.php',
'IcuCollation' => __DIR__ . '/includes/collation/IcuCollation.php',
'IdentityCollation' => __DIR__ . '/includes/collation/IdentityCollation.php',
'SpecialSearchResults': Called before search result display
$term: string of search term
-&$titleMatches: empty or SearchResultSet object
-&$textMatches: empty or SearchResultSet object
+&$titleMatches: empty or ISearchResultSet object
+&$textMatches: empty or ISearchResultSet object
'SpecialSearchResultsPrepend': Called immediately before returning HTML
on the search results page. Useful for including an external search
$canAddInterwiki = (bool)$params['enablerewrites'] && ( $resultPageSet === null );
if ( $canAddInterwiki ) {
$this->addInterwikiResults( $matches, $apiResult, $prop, 'additional',
- SearchResultSet::INLINE_RESULTS );
+ ISearchResultSet::INLINE_RESULTS );
}
// Interwiki results outside main result set
if ( $interwiki && $resultPageSet === null ) {
$this->addInterwikiResults( $matches, $apiResult, $prop, 'interwiki',
- SearchResultSet::SECONDARY_RESULTS );
+ ISearchResultSet::SECONDARY_RESULTS );
}
if ( $resultPageSet === null ) {
/**
* Add interwiki results as a section in query results.
- * @param SearchResultSet $matches
+ * @param ISearchResultSet $matches
* @param ApiResult $apiResult
* @param array $prop Props to extract (as keys)
* @param string $section Section name where results would go
* @return int|null Number of total hits in the data or null if none was produced
*/
private function addInterwikiResults(
- SearchResultSet $matches, ApiResult $apiResult, $prop,
+ ISearchResultSet $matches, ApiResult $apiResult, $prop,
$section, $type
) {
$totalhits = null;
$this->propnames = $propnames;
}
- public function augmentAll( SearchResultSet $resultSet ) {
+ public function augmentAll( ISearchResultSet $resultSet ) {
$titles = $resultSet->extractTitles();
return PageProps::getInstance()->getProperties( $titles, $this->propnames );
}
--- /dev/null
+<?php
+
+/**
+ * @ingroup Search
+ */
+interface ISearchResultSet extends \Countable, \IteratorAggregate {
+ /**
+ * Identifier for interwiki results that are displayed only together with existing main wiki
+ * results.
+ */
+ const SECONDARY_RESULTS = 0;
+
+ /**
+ * Identifier for interwiki results that can be displayed even if no existing main wiki results
+ * exist.
+ */
+ const INLINE_RESULTS = 1;
+
+ /**
+ * @return int
+ */
+ function numRows();
+
+ /**
+ * Some search modes return a total hit count for the query
+ * in the entire article database. This may include pages
+ * in namespaces that would not be matched on the given
+ * settings.
+ *
+ * Return null if no total hits number is supported.
+ *
+ * @return int|null
+ */
+ function getTotalHits();
+
+ /**
+ * Some search modes will run an alternative query that it thinks gives
+ * a better result than the provided search. Returns true if this has
+ * occurred.
+ *
+ * @return bool
+ */
+ function hasRewrittenQuery();
+
+ /**
+ * @return string|null The search the query was internally rewritten to,
+ * or null when the result of the original query was returned.
+ */
+ function getQueryAfterRewrite();
+
+ /**
+ * @return string|null Same as self::getQueryAfterRewrite(), but in HTML
+ * and with changes highlighted. Null when the query was not rewritten.
+ */
+ function getQueryAfterRewriteSnippet();
+
+ /**
+ * Some search modes return a suggested alternate term if there are
+ * no exact hits. Returns true if there is one on this set.
+ *
+ * @return bool
+ */
+ function hasSuggestion();
+
+ /**
+ * @return string|null Suggested query, null if none
+ */
+ function getSuggestionQuery();
+
+ /**
+ * @return string HTML highlighted suggested query, '' if none
+ */
+ function getSuggestionSnippet();
+
+ /**
+ * Return a result set of hits on other (multiple) wikis associated with this one
+ *
+ * @param int $type
+ * @return ISearchResultSet[]
+ */
+ function getInterwikiResults( $type = self::SECONDARY_RESULTS );
+
+ /**
+ * Check if there are results on other wikis
+ *
+ * @param int $type
+ * @return bool
+ */
+ function hasInterwikiResults( $type = self::SECONDARY_RESULTS );
+
+ /**
+ * Did the search contain search syntax? If so, Special:Search won't offer
+ * the user a link to a create a page named by the search string because the
+ * name would contain the search syntax.
+ * @return bool
+ */
+ public function searchContainedSyntax();
+
+ /**
+ * @return bool True when there are more pages of search results available.
+ */
+ public function hasMoreResults();
+
+ /**
+ * @param int $limit Shrink result set to $limit and flag
+ * if more results are available.
+ */
+ public function shrink( $limit );
+
+ /**
+ * Extract all the results in the result set as array.
+ * @return SearchResult[]
+ */
+ public function extractResults();
+
+ /**
+ * Extract all the titles in the result set.
+ * @return Title[]
+ */
+ public function extractTitles();
+
+ /**
+ * Sets augmented data for result set.
+ * @param string $name Extra data item name
+ * @param array[] $data Extra data as PAGEID => data
+ */
+ public function setAugmentedData( $name, $data );
+
+ /**
+ * Returns extra data for specific result and store it in SearchResult object.
+ * @param SearchResult $result
+ */
+ public function augmentResult( SearchResult $result );
+
+ /**
+ * @return int|null The offset the current page starts at. Typically
+ * this should be null to allow the UI to decide on its own, but in
+ * special cases like interleaved AB tests specifying explicitly is
+ * necessary.
+ */
+ public function getOffset();
+}
/**
* Marker class for search engines that can handle their own pagination, by
- * reporting in their SearchResultSet when a next page is available. This
+ * reporting in their ISearchResultSet when a next page is available. This
* only applies to search{Title,Text} and not to completion search.
*
* SearchEngine implementations not implementing this interface will have
/**
* Produce data to augment search result set.
- * @param SearchResultSet $resultSet
+ * @param ISearchResultSet $resultSet
* @return array Data for all results
*/
- public function augmentAll( SearchResultSet $resultSet ) {
+ public function augmentAll( ISearchResultSet $resultSet ) {
$data = [];
foreach ( $resultSet->extractResults() as $result ) {
$id = $result->getTitle()->getArticleID();
interface ResultSetAugmentor {
/**
* Produce data to augment search result set.
- * @param SearchResultSet $resultSet
+ * @param ISearchResultSet $resultSet
* @return array Data for all results
*/
- public function augmentAll( SearchResultSet $resultSet );
+ public function augmentAll( ISearchResultSet $resultSet );
}
/**
* @param string $term
- * @return SearchResultSet|Status|null
+ * @return ISearchResultSet|Status|null
*/
final public function doSearchText( $term ) {
return $this->doSearchTextInDB( $this->extractNamespacePrefix( $term ) );
/**
* @param string $term
- * @return SearchResultSet|null
+ * @return ISearchResultSet|null
*/
final public function doSearchTitle( $term ) {
return $this->doSearchTitleInDB( $this->extractNamespacePrefix( $term ) );
* be converted to final in 1.34. Override self::doSearchText().
*
* @param string $term Raw search term
- * @return SearchResultSet|Status|null
+ * @return ISearchResultSet|Status|null
*/
public function searchText( $term ) {
return $this->maybePaginate( function () use ( $term ) {
* Perform a full text search query and return a result set.
*
* @param string $term Raw search term
- * @return SearchResultSet|Status|null
+ * @return ISearchResultSet|Status|null
* @since 1.32
*/
protected function doSearchText( $term ) {
* be converted to final in 1.34. Override self::doSearchTitle().
*
* @param string $term Raw search term
- * @return SearchResultSet|null
+ * @return ISearchResultSet|null
*/
public function searchTitle( $term ) {
return $this->maybePaginate( function () use ( $term ) {
* Perform a title-only search query and return a result set.
*
* @param string $term Raw search term
- * @return SearchResultSet|null
+ * @return ISearchResultSet|null
* @since 1.32
*/
protected function doSearchTitle( $term ) {
* explicitly implement their own pagination.
*
* @param Closure $fn Takes no arguments
- * @return SearchResultSet|Status<SearchResultSet>|null Result of calling $fn
+ * @return ISearchResultSet|Status<ISearchResultSet>|null Result of calling $fn
*/
private function maybePaginate( Closure $fn ) {
if ( $this instanceof PaginatingSearchEngine ) {
}
$resultSet = null;
- if ( $resultSetOrStatus instanceof SearchResultSet ) {
+ if ( $resultSetOrStatus instanceof ISearchResultSet ) {
$resultSet = $resultSetOrStatus;
} elseif ( $resultSetOrStatus instanceof Status &&
- $resultSetOrStatus->getValue() instanceof SearchResultSet
+ $resultSetOrStatus->getValue() instanceof ISearchResultSet
) {
$resultSet = $resultSetOrStatus->getValue();
}
/**
* Augment search results with extra data.
*
- * @param SearchResultSet $resultSet
+ * @param ISearchResultSet $resultSet
*/
- public function augmentSearchResults( SearchResultSet $resultSet ) {
+ public function augmentSearchResults( ISearchResultSet $resultSet ) {
$setAugmentors = [];
$rowAugmentors = [];
Hooks::run( "SearchResultsAugment", [ &$setAugmentors, &$rowAugmentors ] );
<?php
/**
- * A SearchResultSet wrapper for SearchNearMatcher
+ * A ISearchResultSet wrapper for SearchNearMatcher
*/
class SearchNearMatchResultSet extends SearchResultSet {
/**
/**
* Do a near match (see SearchEngine::getNearMatch) and wrap it into a
- * SearchResultSet.
+ * ISearchResultSet.
*
* @param string $searchterm
- * @return SearchResultSet
+ * @return ISearchResultSet
*/
public function getNearMatchResultSet( $searchterm ) {
return new SearchNearMatchResultSet( $this->getNearMatch( $searchterm ) );
* Return a new SearchResult and initializes it with a title.
*
* @param Title $title
- * @param SearchResultSet|null $parentSet
+ * @param ISearchResultSet|null $parentSet
* @return SearchResult
*/
- public static function newFromTitle( $title, SearchResultSet $parentSet = null ) {
+ public static function newFromTitle( $title, ISearchResultSet $parentSet = null ) {
$result = new static();
$result->initFromTitle( $title );
if ( $parentSet ) {
/**
* @ingroup Search
*/
-class SearchResultSet implements Countable, IteratorAggregate {
-
- /**
- * Identifier for interwiki results that are displayed only together with existing main wiki
- * results.
- */
- const SECONDARY_RESULTS = 0;
-
- /**
- * Identifier for interwiki results that can be displayed even if no existing main wiki results
- * exist.
- */
- const INLINE_RESULTS = 1;
+class SearchResultSet implements ISearchResultSet {
protected $containedSyntax = false;
* Return a result set of hits on other (multiple) wikis associated with this one
*
* @param int $type
- * @return SearchResultSet[]
+ * @return ISearchResultSet[]
*/
function getInterwikiResults( $type = self::SECONDARY_RESULTS ) {
return null;
$hasErrors = $textStatus && $textStatus->getErrors() !== [];
$hasOtherResults = $textMatches &&
- $textMatches->hasInterwikiResults( SearchResultSet::INLINE_RESULTS );
+ $textMatches->hasInterwikiResults( ISearchResultSet::INLINE_RESULTS );
- if ( $textMatches && $textMatches->hasInterwikiResults( SearchResultSet::SECONDARY_RESULTS ) ) {
+ if ( $textMatches && $textMatches->hasInterwikiResults( ISearchResultSet::SECONDARY_RESULTS ) ) {
$out->addHTML( '<div class="searchresults mw-searchresults-has-iw">' );
} else {
$out->addHTML( '<div class="searchresults">' );
/**
* @param Title $title
* @param int $num The number of search results found
- * @param null|SearchResultSet $titleMatches Results from title search
- * @param null|SearchResultSet $textMatches Results from text search
+ * @param null|ISearchResultSet $titleMatches Results from title search
+ * @param null|ISearchResultSet $textMatches Results from text search
*/
protected function showCreateLink( $title, $num, $titleMatches, $textMatches ) {
// show direct page/create link if applicable
namespace MediaWiki\Widget\Search;
+use ISearchResultSet;
use MediaWiki\MediaWikiServices;
use Message;
-use SearchResultSet;
use SpecialSearch;
use Status;
/**
* @param string $term The search term to highlight
* @param int $offset The offset of the first result in the result set
- * @param SearchResultSet|null $titleResultSet Results of searching only page titles
- * @param SearchResultSet|null $textResultSet Results of general full text search.
+ * @param ISearchResultSet|null $titleResultSet Results of searching only page titles
+ * @param ISearchResultSet|null $textResultSet Results of general full text search.
* @return string HTML
*/
public function render(
$term,
$offset,
- SearchResultSet $titleResultSet = null,
- SearchResultSet $textResultSet = null
+ ISearchResultSet $titleResultSet = null,
+ ISearchResultSet $textResultSet = null
) {
$hasTitle = $titleResultSet ? $titleResultSet->numRows() > 0 : false;
$hasText = $textResultSet ? $textResultSet->numRows() > 0 : false;
$hasSecondary = $textResultSet
- ? $textResultSet->hasInterwikiResults( SearchResultSet::SECONDARY_RESULTS )
+ ? $textResultSet->hasInterwikiResults( ISearchResultSet::SECONDARY_RESULTS )
: false;
$hasSecondaryInline = $textResultSet
- ? $textResultSet->hasInterwikiResults( SearchResultSet::INLINE_RESULTS )
+ ? $textResultSet->hasInterwikiResults( ISearchResultSet::INLINE_RESULTS )
: false;
if ( !$hasTitle && !$hasText && !$hasSecondary && !$hasSecondaryInline ) {
}
if ( $hasSecondaryInline ) {
- $iwResults = $textResultSet->getInterwikiResults( SearchResultSet::INLINE_RESULTS );
+ $iwResults = $textResultSet->getInterwikiResults( ISearchResultSet::INLINE_RESULTS );
foreach ( $iwResults as $interwiki => $results ) {
if ( $results instanceof Status || $results->numRows() === 0 ) {
// ignore bad interwikis for now
if ( $hasSecondary ) {
$out .= $this->sidebarWidget->render(
$term,
- $textResultSet->getInterwikiResults( SearchResultSet::SECONDARY_RESULTS )
+ $textResultSet->getInterwikiResults( ISearchResultSet::SECONDARY_RESULTS )
);
}
}
/**
- * @param SearchResultSet $resultSet The search results to render
+ * @param ISearchResultSet $resultSet The search results to render
* @param int $offset Offset of the first result in $resultSet
* @return string HTML
*/
- protected function renderResultSet( SearchResultSet $resultSet, $offset ) {
+ protected function renderResultSet( ISearchResultSet $resultSet, $offset ) {
$hits = [];
foreach ( $resultSet as $result ) {
$hits[] = $this->resultWidget->render( $result, $offset++ );
namespace MediaWiki\Widget\Search;
use HtmlArmor;
-use SearchResultSet;
+use ISearchResultSet;
use SpecialSearch;
/**
/**
* @param string $term The user provided search term
- * @param SearchResultSet $resultSet
+ * @param ISearchResultSet $resultSet
* @return string HTML
*/
- public function render( $term, SearchResultSet $resultSet ) {
+ public function render( $term, ISearchResultSet $resultSet ) {
if ( $resultSet->hasRewrittenQuery() ) {
$html = $this->rewrittenHtml( $term, $resultSet );
} elseif ( $resultSet->hasSuggestion() ) {
* rewritten, and the results of the rewritten query are being returned.
*
* @param string $term The users search input
- * @param SearchResultSet $resultSet The response to the search request
+ * @param ISearchResultSet $resultSet The response to the search request
* @return string HTML Links the user to their original $term query, and the
* one suggested by $resultSet
*/
- protected function rewrittenHtml( $term, SearchResultSet $resultSet ) {
+ protected function rewrittenHtml( $term, ISearchResultSet $resultSet ) {
$params = [
'search' => $resultSet->getQueryAfterRewrite(),
// Don't magic this link into a 'go' link, it should always
* a query that might give more/better results than their current
* query.
*
- * @param SearchResultSet $resultSet
+ * @param ISearchResultSet $resultSet
* @return string HTML
*/
- protected function suggestionHtml( SearchResultSet $resultSet ) {
+ protected function suggestionHtml( ISearchResultSet $resultSet ) {
$params = [
'search' => $resultSet->getSuggestionQuery(),
'fulltext' => 1,
use MediaWiki\Interwiki\InterwikiLookup;
use MediaWiki\Linker\LinkRenderer;
-use SearchResultSet;
+use ISearchResultSet;
use SpecialSearch;
use Title;
use Html;
use OOUI;
/**
- * Renders one or more SearchResultSets into a sidebar grouped by
+ * Renders one or more ISearchResultSets into a sidebar grouped by
* interwiki prefix. Includes a per-wiki header indicating where
* the results are from.
*/
/**
* @param string $term User provided search term
- * @param SearchResultSet|SearchResultSet[] $resultSets List of interwiki
+ * @param ISearchResultSet|ISearchResultSet[] $resultSets List of interwiki
* results to render.
* @return string HTML
*/
namespace MediaWiki\Widget\Search;
-use SearchResultSet;
+use ISearchResultSet;
/**
* Renders a set of search results to HTML
interface SearchResultSetWidget {
/**
* @param string $term User provided search term
- * @param SearchResultSet|SearchResultSet[] $resultSets List of interwiki
+ * @param ISearchResultSet|ISearchResultSet[] $resultSets List of interwiki
* results to render.
* @return string HTML
*/
use MediaWiki\Interwiki\InterwikiLookup;
use MediaWiki\Linker\LinkRenderer;
-use SearchResultSet;
+use ISearchResultSet;
use SpecialSearch;
use Title;
use Html;
/**
- * Renders one or more SearchResultSets into a sidebar grouped by
+ * Renders one or more ISearchResultSets into a sidebar grouped by
* interwiki prefix. Includes a per-wiki header indicating where
* the results are from.
*
/**
* @param string $term User provided search term
- * @param SearchResultSet|SearchResultSet[] $resultSets List of interwiki
+ * @param ISearchResultSet|ISearchResultSet[] $resultSets List of interwiki
* results to render.
* @return string HTML
*/
'one wiki response' => [
[ 'utwiki' => [ 'Qwerty' ] ],
[
- SearchResultSet::SECONDARY_RESULTS => [
+ ISearchResultSet::SECONDARY_RESULTS => [
'utwiki' => new MockSearchResultSet( [
$this->mockResultClosure(
'Qwerty',
'wgCapitalLinks' => true,
'wgCapitalLinkOverrides' => [
NS_CATEGORY => false // for testCompletionSearchMustRespectCapitalLinkOverrides
- ]
+ ],
] );
$lb = LoadBalancerSingle::newFromConnection( $this->db );
'wgCapitalLinks' => true,
'wgCapitalLinkOverrides' => [
NS_CATEGORY => false // for testCompletionSearchMustRespectCapitalLinkOverrides
- ]
+ ],
] );
$this->insertPage( 'Not_Main_Page', 'This is not a main page' );
$mockField =
$this->getMockBuilder( SearchIndexFieldDefinition::class )->setConstructorArgs( [
$name,
- $type
+ $type,
] )->getMock();
$mockField->expects( $this->any() )->method( 'getMapping' )->willReturn( [
$setAugmentor = $this->createMock( ResultSetAugmentor::class );
$setAugmentor->expects( $this->once() )
->method( 'augmentAll' )
- ->willReturnCallback( function ( SearchResultSet $resultSet ) {
+ ->willReturnCallback( function ( ISearchResultSet $resultSet ) {
$data = [];
+ /** @var SearchResult $result */
foreach ( $resultSet as $result ) {
$id = $result->getTitle()->getArticleID();
$data[$id] = "Result:$id:" . $result->getTitle()->getText();
[
'query' => 'foo',
],
- false
+ false,
],
'empty' => [
[
'query' => 'all:test',
'withAll' => false,
],
- false
+ false,
],
'ns only' => [
[
'query' => 'help:',
],
- [ '', [ NS_HELP ] ]
+ [ '', [ NS_HELP ] ],
],
'all only' => [
[
'query' => 'all:',
'withAll' => true,
],
- [ '', null ]
+ [ '', null ],
],
'all wins over namespace when first' => [
[
'query' => 'all:help:test',
'withAll' => true,
],
- [ 'help:test', null ]
+ [ 'help:test', null ],
],
'ns wins over all when first' => [
[
'query' => 'help:all:test',
'withAll' => true,
],
- [ 'all:test', [ NS_HELP ] ]
+ [ 'all:test', [ NS_HELP ] ],
],
];
}
class MockSearchEngine extends SearchEngine {
/** @var SearchResult[][] */
private static $results = [];
- /** @var SearchResultSet[][] */
+ /** @var ISearchResultSet[][] */
private static $interwikiResults = [];
public static function clearMockResults() {
}
/**
- * @param SearchResultSet[][] $interwikiResults
+ * @param ISearchResultSet[][] $interwikiResults
*/
public static function setMockInterwikiResults( array $interwikiResults ) {
self::$interwikiResults = $interwikiResults;
/**
* @param SearchResult[]|callable[] $results
- * @param SearchResultSet[][]|callable[][] $interwikiResults Map from result type
+ * @param ISearchResultSet[][]|callable[][] $interwikiResults Map from result type
* to list of results for that type.
*/
public function __construct( array $results, array $interwikiResults = [] ) {