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