Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 132
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
SuggestionListManager
0.00% covered (danger)
0.00%
0 / 132
0.00% covered (danger)
0.00%
0 / 10
462
0.00% covered (danger)
0.00%
0 / 1
 removeTitles
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 getListByConds
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 getListByName
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getListById
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getDiscardedSuggestions
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getFavoriteSuggestions
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 getSuggestionsByListName
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
20
 getPublicSuggestions
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 getSuggestionsByType
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
12
 getSuggestionsInList
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace ContentTranslation;
4
5use MediaWiki\MediaWikiServices;
6use MediaWiki\Title\Title;
7use Wikimedia\Rdbms\IConnectionProvider;
8use Wikimedia\Rdbms\SelectQueryBuilder;
9
10class 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}