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    /** @var bool */
34    protected $containedSyntax = false;
35
36    /**
37     * Cache of titles.
38     * Lists titles of the result set, in the same order as results.
39     * @var Title[]|null
40     */
41    private $titles;
42
43    /**
44     * Cache of results - serialization of the result iterator
45     * as an array.
46     * @var SearchResult[]
47     */
48    protected $results;
49
50    /**
51     * @var bool True when there are more pages of search results available.
52     */
53    private $hasMoreResults;
54
55    /**
56     * @param bool $containedSyntax True when query is not requesting a simple
57     *  term match
58     * @param bool $hasMoreResults True when there are more pages of search
59     *  results available.
60     */
61    public function __construct( $containedSyntax = false, $hasMoreResults = false ) {
62        if ( static::class === self::class ) {
63            // This class will eventually be abstract. SearchEngine implementations
64            // already have to extend this class anyways to provide the actual
65            // search results.
66            wfDeprecated( __METHOD__, '1.32' );
67        }
68        $this->containedSyntax = $containedSyntax;
69        $this->hasMoreResults = $hasMoreResults;
70    }
71
72    public function numRows() {
73        return $this->count();
74    }
75
76    final public function count(): int {
77        return count( $this->extractResults() );
78    }
79
80    /**
81     * Some search modes return a total hit count for the query
82     * in the entire article database. This may include pages
83     * in namespaces that would not be matched on the given
84     * settings.
85     *
86     * Return null if no total hits number is supported.
87     *
88     * @return int|null
89     */
90    public function getTotalHits() {
91        return null;
92    }
93
94    /**
95     * Some search modes will run an alternative query that it thinks gives
96     * a better result than the provided search. Returns true if this has
97     * occurred.
98     *
99     * @return bool
100     */
101    public function hasRewrittenQuery() {
102        return false;
103    }
104
105    /**
106     * @return string|null The search the query was internally rewritten to,
107     *  or null when the result of the original query was returned.
108     */
109    public function getQueryAfterRewrite() {
110        return null;
111    }
112
113    /**
114     * @return HtmlArmor|string|null Same as self::getQueryAfterRewrite(), but
115     *  with changes highlighted if HtmlArmor is returned. Null when the query
116     *  was not rewritten.
117     */
118    public function getQueryAfterRewriteSnippet() {
119        return null;
120    }
121
122    /**
123     * Some search modes return a suggested alternate term if there are
124     * no exact hits. Returns true if there is one on this set.
125     *
126     * @return bool
127     */
128    public function hasSuggestion() {
129        return false;
130    }
131
132    /**
133     * @return string|null Suggested query, null if none
134     */
135    public function getSuggestionQuery() {
136        return null;
137    }
138
139    /**
140     * @return HtmlArmor|string HTML highlighted suggested query, '' if none
141     */
142    public function getSuggestionSnippet() {
143        return '';
144    }
145
146    /**
147     * Return a result set of hits on other (multiple) wikis associated with this one
148     *
149     * @param int $type
150     * @return ISearchResultSet[]|null
151     */
152    public function getInterwikiResults( $type = self::SECONDARY_RESULTS ) {
153        return null;
154    }
155
156    /**
157     * Check if there are results on other wikis
158     *
159     * @param int $type
160     * @return bool
161     */
162    public function hasInterwikiResults( $type = self::SECONDARY_RESULTS ) {
163        return false;
164    }
165
166    /**
167     * Did the search contain search syntax?  If so, Special:Search won't offer
168     * the user a link to a create a page named by the search string because the
169     * name would contain the search syntax.
170     * @return bool
171     */
172    public function searchContainedSyntax() {
173        return $this->containedSyntax;
174    }
175
176    /**
177     * @return bool True when there are more pages of search results available.
178     */
179    public function hasMoreResults() {
180        return $this->hasMoreResults;
181    }
182
183    /**
184     * @param int $limit Shrink result set to $limit and flag
185     *  if more results are available.
186     */
187    public function shrink( $limit ) {
188        if ( $this->count() > $limit ) {
189            $this->hasMoreResults = true;
190            // shrinking result set for implementations that
191            // have not implemented extractResults and use
192            // the default cache location. Other implementations
193            // must override this as well.
194            if ( is_array( $this->results ) ) {
195                $this->results = array_slice( $this->results, 0, $limit );
196                $this->titles = null;
197            } else {
198                throw new \UnexpectedValueException(
199                    "When overriding result store extending classes must "
200                    . " also override " . __METHOD__ );
201            }
202        }
203    }
204
205    /**
206     * Extract all the results in the result set as array.
207     * @return SearchResult[]
208     */
209    public function extractResults() {
210        if ( $this->results === null ) {
211            $this->results = [];
212            if ( $this->numRows() == 0 ) {
213                // Don't bother if we've got empty result
214                return $this->results;
215            }
216            $this->rewind();
217            foreach ( $this as $result ) {
218                $this->results[] = $result;
219            }
220            $this->rewind();
221        }
222        return $this->results;
223    }
224
225    /**
226     * Extract all the titles in the result set.
227     * @return Title[]
228     */
229    public function extractTitles() {
230        if ( $this->titles === null ) {
231            if ( $this->numRows() == 0 ) {
232                // Don't bother if we've got empty result
233                $this->titles = [];
234            } else {
235                $this->titles = array_map(
236                    static function ( SearchResult $result ) {
237                        return $result->getTitle();
238                    },
239                    $this->extractResults() );
240            }
241        }
242        return $this->titles;
243    }
244}