Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 132 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
SuggestionListManager | |
0.00% |
0 / 132 |
|
0.00% |
0 / 10 |
462 | |
0.00% |
0 / 1 |
removeTitles | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
getListByConds | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
getListByName | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getListById | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getDiscardedSuggestions | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getFavoriteSuggestions | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
6 | |||
getSuggestionsByListName | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
20 | |||
getPublicSuggestions | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 | |||
getSuggestionsByType | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
12 | |||
getSuggestionsInList | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | namespace ContentTranslation; |
4 | |
5 | use MediaWiki\MediaWikiServices; |
6 | use MediaWiki\Title\Title; |
7 | use Wikimedia\Rdbms\IConnectionProvider; |
8 | use Wikimedia\Rdbms\SelectQueryBuilder; |
9 | |
10 | class SuggestionListManager { |
11 | /** |
12 | * @param string $sourceLanguage |
13 | * @param array $titles |
14 | */ |
15 | public function removeTitles( $sourceLanguage, array $titles ) { |
16 | if ( $titles === [] ) { |
17 | return; |
18 | } |
19 | |
20 | /** @var IConnectionProvider $connectionProvider */ |
21 | $connectionProvider = MediaWikiServices::getInstance()->getService( 'ContentTranslation.ConnectionProvider' ); |
22 | $dbw = $connectionProvider->getPrimaryDatabase(); |
23 | $dbw->newDeleteQueryBuilder() |
24 | ->deleteFrom( 'cx_suggestions' ) |
25 | ->where( [ |
26 | 'cxs_title' => $titles, |
27 | 'cxs_source_language' => $sourceLanguage, |
28 | ] ) |
29 | ->caller( __METHOD__ ) |
30 | ->execute(); |
31 | } |
32 | |
33 | /** |
34 | * @param array $conds |
35 | * @return SuggestionList|null |
36 | */ |
37 | protected function getListByConds( array $conds ) { |
38 | /** @var IConnectionProvider $connectionProvider */ |
39 | $connectionProvider = MediaWikiServices::getInstance()->getService( 'ContentTranslation.ConnectionProvider' ); |
40 | $dbr = $connectionProvider->getReplicaDatabase(); |
41 | $row = $dbr->newSelectQueryBuilder() |
42 | ->select( '*' ) |
43 | ->from( 'cx_lists' ) |
44 | ->where( $conds ) |
45 | ->caller( __METHOD__ ) |
46 | ->fetchRow(); |
47 | |
48 | if ( $row ) { |
49 | return SuggestionList::newFromRow( $row ); |
50 | } |
51 | |
52 | return null; |
53 | } |
54 | |
55 | /** |
56 | * @param string $name |
57 | * @param int $owner |
58 | * @return SuggestionList|null |
59 | */ |
60 | public function getListByName( $name, $owner = 0 ) { |
61 | $conds = [ |
62 | 'cxl_name' => $name, |
63 | 'cxl_owner' => $owner, |
64 | ]; |
65 | |
66 | return $this->getListByConds( $conds ); |
67 | } |
68 | |
69 | /** |
70 | * @param int $id |
71 | * @return SuggestionList|null |
72 | */ |
73 | public function getListById( $id ) { |
74 | $conds = [ |
75 | 'cxl_id' => $id, |
76 | 'cxl_owner' => 0, |
77 | ]; |
78 | |
79 | return $this->getListByConds( $conds ); |
80 | } |
81 | |
82 | /** |
83 | * Get the titles discarded by the user between a language pair |
84 | * |
85 | * @param int $owner Owner's global user id. |
86 | * @param string $from Source language code. |
87 | * @param string $to Target language code. |
88 | * @return Title[] |
89 | */ |
90 | public function getDiscardedSuggestions( $owner, $from, $to ) { |
91 | $titles = []; |
92 | $listName = 'cx-suggestionlist-discarded'; |
93 | |
94 | $suggestions = $this->getSuggestionsByListName( $owner, $listName, $from, $to ); |
95 | |
96 | foreach ( $suggestions as $suggestion ) { |
97 | $titles[] = $suggestion->getTitle(); |
98 | } |
99 | |
100 | return $titles; |
101 | } |
102 | |
103 | /** |
104 | * Get suggestions markes as favorite by the translator. |
105 | * |
106 | * @param int $owner Owner's global user id. |
107 | * @return array Lists and suggestions |
108 | */ |
109 | public function getFavoriteSuggestions( $owner ) { |
110 | $lists = []; |
111 | $listName = 'cx-suggestionlist-favorite'; |
112 | $favoriteList = $this->getListByName( $listName, $owner ); |
113 | $suggestions = $this->getSuggestionsByListName( $owner, $listName ); |
114 | |
115 | if ( $favoriteList ) { |
116 | $lists[] = $favoriteList; |
117 | } |
118 | |
119 | return [ |
120 | 'lists' => $lists, |
121 | 'suggestions' => $suggestions, |
122 | ]; |
123 | } |
124 | |
125 | /** |
126 | * Get the suggestions by list name for the given owner. |
127 | * |
128 | * @param int $owner Owner's global user id. |
129 | * @param string $listName |
130 | * @param string|null $from Source language code. |
131 | * @param string|null $to Target language code. |
132 | * @return Suggestion[] Suggestions |
133 | */ |
134 | private function getSuggestionsByListName( $owner, $listName, $from = null, $to = null ) { |
135 | /** @var IConnectionProvider $connectionProvider */ |
136 | $connectionProvider = MediaWikiServices::getInstance()->getService( 'ContentTranslation.ConnectionProvider' ); |
137 | $dbr = $connectionProvider->getReplicaDatabase(); |
138 | $suggestions = []; |
139 | $conds = [ |
140 | 'cxl_name' => $listName, |
141 | 'cxl_owner' => $owner, |
142 | ]; |
143 | |
144 | if ( $from !== null ) { |
145 | $conds[ 'cxs_source_language' ] = $from; |
146 | } |
147 | if ( $to !== null ) { |
148 | $conds[ 'cxs_target_language' ] = $to; |
149 | } |
150 | |
151 | $res = $dbr->newSelectQueryBuilder() |
152 | ->select( [ 'cxs_list_id', 'cxs_title', 'cxs_source_language', 'cxs_target_language' ] ) |
153 | ->from( 'cx_suggestions' ) |
154 | ->join( 'cx_lists', null, 'cxs_list_id = cxl_id' ) |
155 | ->where( $conds ) |
156 | ->caller( __METHOD__ ) |
157 | ->fetchResultSet(); |
158 | |
159 | foreach ( $res as $row ) { |
160 | $suggestions[] = Suggestion::newFromRow( $row ); |
161 | } |
162 | |
163 | return $suggestions; |
164 | } |
165 | |
166 | /** |
167 | * Get public (non-personalized) suggestions. |
168 | * |
169 | * @param string $from Source language code. |
170 | * @param string $to Target language code. |
171 | * @param int $limit How many suggestions to fetch. |
172 | * @param int $offset Offset from the beginning to fetch. |
173 | * @param int $seed Seed to use with randomizing of results. |
174 | * @return array Lists and suggestions |
175 | */ |
176 | public function getPublicSuggestions( $from, $to, $limit, $offset, $seed ) { |
177 | return $this->getSuggestionsByType( |
178 | [ |
179 | SuggestionList::TYPE_CATEGORY, |
180 | SuggestionList::TYPE_FEATURED |
181 | ], |
182 | $from, |
183 | $to, |
184 | $limit, |
185 | $offset, |
186 | $seed |
187 | ); |
188 | } |
189 | |
190 | /** |
191 | * Get public suggestions by list type |
192 | * |
193 | * @param int|int[] $type List type. |
194 | * @param string $from Source language code. |
195 | * @param string $to Target language code. |
196 | * @param int $limit How many suggestions to fetch. |
197 | * @param int|null $offset Offset from the beginning to fetch. |
198 | * @param int|null $seed Seed to use with randomizing of results. |
199 | * @return array Lists and suggestions |
200 | */ |
201 | public function getSuggestionsByType( $type, $from, $to, $limit, $offset = null, $seed = null ) { |
202 | /** @var IConnectionProvider $connectionProvider */ |
203 | $connectionProvider = MediaWikiServices::getInstance()->getService( 'ContentTranslation.ConnectionProvider' ); |
204 | $dbr = $connectionProvider->getReplicaDatabase(); |
205 | |
206 | $lists = []; |
207 | $suggestions = []; |
208 | |
209 | $res = $dbr->newSelectQueryBuilder() |
210 | ->select( '*' ) |
211 | ->from( 'cx_lists' ) |
212 | ->where( [ |
213 | 'cxl_type' => $type, |
214 | 'cxl_public' => true, |
215 | ] ) |
216 | ->caller( __METHOD__ ) |
217 | ->orderBy( 'cxl_type', SelectQueryBuilder::SORT_DESC ) |
218 | ->fetchResultSet(); |
219 | |
220 | foreach ( $res as $row ) { |
221 | $list = SuggestionList::newFromRow( $row ); |
222 | $suggestionsInList = $this->getSuggestionsInList( |
223 | $list->getId(), $from, $to, $limit, $offset, $seed |
224 | ); |
225 | if ( !count( $suggestionsInList ) ) { |
226 | continue; |
227 | } |
228 | $lists[$list->getId()] = $list; |
229 | $suggestions = array_merge( |
230 | $suggestions, |
231 | $suggestionsInList |
232 | ); |
233 | } |
234 | |
235 | return [ |
236 | 'lists' => $lists, |
237 | 'suggestions' => $suggestions, |
238 | ]; |
239 | } |
240 | |
241 | /** |
242 | * Get the suggestions by list id |
243 | * |
244 | * @param int $listId |
245 | * @param string $from Source language code. |
246 | * @param string $to Target language code. |
247 | * @param int $limit How many suggestions to fetch. |
248 | * @param int $offset Offset from the beginning to fetch. |
249 | * @param int $seed Seed to use with randomizing of results. |
250 | * @return Suggestion[] Suggestions |
251 | */ |
252 | public function getSuggestionsInList( $listId, $from, $to, $limit, $offset, $seed ) { |
253 | $suggestions = []; |
254 | /** @var IConnectionProvider $connectionProvider */ |
255 | $connectionProvider = MediaWikiServices::getInstance()->getService( 'ContentTranslation.ConnectionProvider' ); |
256 | $dbr = $connectionProvider->getReplicaDatabase(); |
257 | |
258 | $seed = (int)$seed; |
259 | |
260 | $queryBuilder = $dbr->newSelectQueryBuilder() |
261 | ->select( '*' ) |
262 | ->from( 'cx_suggestions' ) |
263 | ->where( [ |
264 | 'cxs_source_language' => $from, |
265 | 'cxs_target_language' => $to, |
266 | 'cxs_list_id' => $listId |
267 | ] ) |
268 | ->limit( $limit ) |
269 | ->orderBy( "RAND( $seed )" ) |
270 | ->caller( __METHOD__ ); |
271 | |
272 | if ( $offset ) { |
273 | $queryBuilder->offset( $offset ); |
274 | } |
275 | |
276 | $res = $queryBuilder->fetchResultSet(); |
277 | |
278 | foreach ( $res as $row ) { |
279 | $suggestions[] = Suggestion::newFromRow( $row ); |
280 | } |
281 | |
282 | return $suggestions; |
283 | } |
284 | } |