]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/search/SearchSuggestionSet.php
MediaWiki 1.30.2-scripts2
[autoinstalls/mediawiki.git] / includes / search / SearchSuggestionSet.php
1 <?php
2
3 /**
4  * Search suggestion sets
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  * http://www.gnu.org/copyleft/gpl.html
20  */
21
22 /**
23  * A set of search suggestions.
24  * The set is always ordered by score, with the best match first.
25  */
26 class SearchSuggestionSet {
27         /**
28          * @var SearchSuggestion[]
29          */
30         private $suggestions = [];
31
32         /**
33          *
34          * @var array
35          */
36         private $pageMap = [];
37
38         /**
39          * Builds a new set of suggestions.
40          *
41          * NOTE: the array should be sorted by score (higher is better),
42          * in descending order.
43          * SearchSuggestionSet will not try to re-order this input array.
44          * Providing an unsorted input array is a mistake and will lead to
45          * unexpected behaviors.
46          *
47          * @param SearchSuggestion[] $suggestions (must be sorted by score)
48          */
49         public function __construct( array $suggestions ) {
50                 foreach ( $suggestions as $suggestion ) {
51                         $pageID = $suggestion->getSuggestedTitleID();
52                         if ( $pageID && empty( $this->pageMap[$pageID] ) ) {
53                                 $this->pageMap[$pageID] = true;
54                         }
55                         $this->suggestions[] = $suggestion;
56                 }
57         }
58
59         /**
60          * Get the list of suggestions.
61          * @return SearchSuggestion[]
62          */
63         public function getSuggestions() {
64                 return $this->suggestions;
65         }
66
67         /**
68          * Call array_map on the suggestions array
69          * @param callback $callback
70          * @return array
71          */
72         public function map( $callback ) {
73                 return array_map( $callback, $this->suggestions );
74         }
75
76         /**
77          * Add a new suggestion at the end.
78          * If the score of the new suggestion is greater than the worst one,
79          * the new suggestion score will be updated (worst - 1).
80          *
81          * @param SearchSuggestion $suggestion
82          */
83         public function append( SearchSuggestion $suggestion ) {
84                 $pageID = $suggestion->getSuggestedTitleID();
85                 if ( $pageID && isset( $this->pageMap[$pageID] ) ) {
86                         return;
87                 }
88                 if ( $this->getSize() > 0 && $suggestion->getScore() >= $this->getWorstScore() ) {
89                         $suggestion->setScore( $this->getWorstScore() - 1 );
90                 }
91                 $this->suggestions[] = $suggestion;
92                 if ( $pageID ) {
93                         $this->pageMap[$pageID] = true;
94                 }
95         }
96
97         /**
98          * Add suggestion set to the end of the current one.
99          * @param SearchSuggestionSet $set
100          */
101         public function appendAll( SearchSuggestionSet $set ) {
102                 foreach ( $set->getSuggestions() as $sugg ) {
103                         $this->append( $sugg );
104                 }
105         }
106
107         /**
108          * Move the suggestion at index $key to the first position
109          * @param string $key
110          */
111         public function rescore( $key ) {
112                 $removed = array_splice( $this->suggestions, $key, 1 );
113                 unset( $this->pageMap[$removed[0]->getSuggestedTitleID()] );
114                 $this->prepend( $removed[0] );
115         }
116
117         /**
118          * Add a new suggestion at the top. If the new suggestion score
119          * is lower than the best one its score will be updated (best + 1)
120          * @param SearchSuggestion $suggestion
121          */
122         public function prepend( SearchSuggestion $suggestion ) {
123                 $pageID = $suggestion->getSuggestedTitleID();
124                 if ( $pageID && isset( $this->pageMap[$pageID] ) ) {
125                         return;
126                 }
127                 if ( $this->getSize() > 0 && $suggestion->getScore() <= $this->getBestScore() ) {
128                         $suggestion->setScore( $this->getBestScore() + 1 );
129                 }
130                 array_unshift( $this->suggestions,  $suggestion );
131                 if ( $pageID ) {
132                         $this->pageMap[$pageID] = true;
133                 }
134         }
135
136         /**
137          * @return float the best score in this suggestion set
138          */
139         public function getBestScore() {
140                 if ( empty( $this->suggestions ) ) {
141                         return 0;
142                 }
143                 return $this->suggestions[0]->getScore();
144         }
145
146         /**
147          * @return float the worst score in this set
148          */
149         public function getWorstScore() {
150                 if ( empty( $this->suggestions ) ) {
151                         return 0;
152                 }
153                 return end( $this->suggestions )->getScore();
154         }
155
156         /**
157          * @return int the number of suggestion in this set
158          */
159         public function getSize() {
160                 return count( $this->suggestions );
161         }
162
163         /**
164          * Remove any extra elements in the suggestions set
165          * @param int $limit the max size of this set.
166          */
167         public function shrink( $limit ) {
168                 if ( count( $this->suggestions ) > $limit ) {
169                         $this->suggestions = array_slice( $this->suggestions, 0, $limit );
170                 }
171         }
172
173         /**
174          * Builds a new set of suggestion based on a title array.
175          * Useful when using a backend that supports only Titles.
176          *
177          * NOTE: Suggestion scores will be generated.
178          *
179          * @param Title[] $titles
180          * @return SearchSuggestionSet
181          */
182         public static function fromTitles( array $titles ) {
183                 $score = count( $titles );
184                 $suggestions = array_map( function ( $title ) use ( &$score ) {
185                         return SearchSuggestion::fromTitle( $score--, $title );
186                 }, $titles );
187                 return new SearchSuggestionSet( $suggestions );
188         }
189
190         /**
191          * Builds a new set of suggestion based on a string array.
192          *
193          * NOTE: Suggestion scores will be generated.
194          *
195          * @param string[] $titles
196          * @return SearchSuggestionSet
197          */
198         public static function fromStrings( array $titles ) {
199                 $score = count( $titles );
200                 $suggestions = array_map( function ( $title ) use ( &$score ) {
201                         return SearchSuggestion::fromText( $score--, $title );
202                 }, $titles );
203                 return new SearchSuggestionSet( $suggestions );
204         }
205
206         /**
207          * @return SearchSuggestionSet an empty suggestion set
208          */
209         public static function emptySuggestionSet() {
210                 return new SearchSuggestionSet( [] );
211         }
212 }