Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
16.28% covered (danger)
16.28%
7 / 43
11.76% covered (danger)
11.76%
2 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
SearchResultSet
16.28% covered (danger)
16.28%
7 / 43
11.76% covered (danger)
11.76%
2 / 17
391.76
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 numRows
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 count
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTotalHits
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasRewrittenQuery
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getQueryAfterRewrite
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getQueryAfterRewriteSnippet
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasSuggestion
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSuggestionQuery
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSuggestionSnippet
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInterwikiResults
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasInterwikiResults
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 searchContainedSyntax
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasMoreResults
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 shrink
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
3.47
 extractResults
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 extractTitles
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * Search result sets
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup Search
22 */
23
24use MediaWiki\Title\Title;
25
26/**
27 * @ingroup Search
28 */
29class SearchResultSet extends BaseSearchResultSet {
30
31    use SearchResultSetTrait;
32
33    protected $containedSyntax = false;
34
35    /**
36     * Cache of titles.
37     * Lists titles of the result set, in the same order as results.
38     * @var Title[]|null
39     */
40    private $titles;
41
42    /**
43     * Cache of results - serialization of the result iterator
44     * as an array.
45     * @var SearchResult[]
46     */
47    protected $results;
48
49    /**
50     * @var bool True when there are more pages of search results available.
51     */
52    private $hasMoreResults;
53
54    /**
55     * @param bool $containedSyntax True when query is not requesting a simple
56     *  term match
57     * @param bool $hasMoreResults True when there are more pages of search
58     *  results available.
59     */
60    public function __construct( $containedSyntax = false, $hasMoreResults = false ) {
61        if ( static::class === self::class ) {
62            // This class will eventually be abstract. SearchEngine implementations
63            // already have to extend this class anyways to provide the actual
64            // search results.
65            wfDeprecated( __METHOD__, '1.32' );
66        }
67        $this->containedSyntax = $containedSyntax;
68        $this->hasMoreResults = $hasMoreResults;
69    }
70
71    public function numRows() {
72        return $this->count();
73    }
74
75    final public function count(): int {
76        return count( $this->extractResults() );
77    }
78
79    /**
80     * Some search modes return a total hit count for the query
81     * in the entire article database. This may include pages
82     * in namespaces that would not be matched on the given
83     * settings.
84     *
85     * Return null if no total hits number is supported.
86     *
87     * @return int|null
88     */
89    public function getTotalHits() {
90        return null;
91    }
92
93    /**
94     * Some search modes will run an alternative query that it thinks gives
95     * a better result than the provided search. Returns true if this has
96     * occurred.
97     *
98     * @return bool
99     */
100    public function hasRewrittenQuery() {
101        return false;
102    }
103
104    /**
105     * @return string|null The search the query was internally rewritten to,
106     *  or null when the result of the original query was returned.
107     */
108    public function getQueryAfterRewrite() {
109        return null;
110    }
111
112    /**
113     * @return HtmlArmor|string|null Same as self::getQueryAfterRewrite(), but
114     *  with changes highlighted if HtmlArmor is returned. Null when the query
115     *  was not rewritten.
116     */
117    public function getQueryAfterRewriteSnippet() {
118        return null;
119    }
120
121    /**
122     * Some search modes return a suggested alternate term if there are
123     * no exact hits. Returns true if there is one on this set.
124     *
125     * @return bool
126     */
127    public function hasSuggestion() {
128        return false;
129    }
130
131    /**
132     * @return string|null Suggested query, null if none
133     */
134    public function getSuggestionQuery() {
135        return null;
136    }
137
138    /**
139     * @return HtmlArmor|string HTML highlighted suggested query, '' if none
140     */
141    public function getSuggestionSnippet() {
142        return '';
143    }
144
145    /**
146     * Return a result set of hits on other (multiple) wikis associated with this one
147     *
148     * @param int $type
149     * @return ISearchResultSet[]|null
150     */
151    public function getInterwikiResults( $type = self::SECONDARY_RESULTS ) {
152        return null;
153    }
154
155    /**
156     * Check if there are results on other wikis
157     *
158     * @param int $type
159     * @return bool
160     */
161    public function hasInterwikiResults( $type = self::SECONDARY_RESULTS ) {
162        return false;
163    }
164
165    /**
166     * Did the search contain search syntax?  If so, Special:Search won't offer
167     * the user a link to a create a page named by the search string because the
168     * name would contain the search syntax.
169     * @return bool
170     */
171    public function searchContainedSyntax() {
172        return $this->containedSyntax;
173    }
174
175    /**
176     * @return bool True when there are more pages of search results available.
177     */
178    public function hasMoreResults() {
179        return $this->hasMoreResults;
180    }
181
182    /**
183     * @param int $limit Shrink result set to $limit and flag
184     *  if more results are available.
185     */
186    public function shrink( $limit ) {
187        if ( $this->count() > $limit ) {
188            $this->hasMoreResults = true;
189            // shrinking result set for implementations that
190            // have not implemented extractResults and use
191            // the default cache location. Other implementations
192            // must override this as well.
193            if ( is_array( $this->results ) ) {
194                $this->results = array_slice( $this->results, 0, $limit );
195                $this->titles = null;
196            } else {
197                throw new \UnexpectedValueException(
198                    "When overriding result store extending classes must "
199                    . " also override " . __METHOD__ );
200            }
201        }
202    }
203
204    /**
205     * Extract all the results in the result set as array.
206     * @return SearchResult[]
207     */
208    public function extractResults() {
209        if ( $this->results === null ) {
210            $this->results = [];
211            if ( $this->numRows() == 0 ) {
212                // Don't bother if we've got empty result
213                return $this->results;
214            }
215            $this->rewind();
216            while ( $result = $this->next() ) {
217                $this->results[] = $result;
218            }
219            $this->rewind();
220        }
221        return $this->results;
222    }
223
224    /**
225     * Extract all the titles in the result set.
226     * @return Title[]
227     */
228    public function extractTitles() {
229        if ( $this->titles === null ) {
230            if ( $this->numRows() == 0 ) {
231                // Don't bother if we've got empty result
232                $this->titles = [];
233            } else {
234                $this->titles = array_map(
235                    static function ( SearchResult $result ) {
236                        return $result->getTitle();
237                    },
238                    $this->extractResults() );
239            }
240        }
241        return $this->titles;
242    }
243}