Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 146 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
ApiQueryAllMessages | |
0.00% |
0 / 146 |
|
0.00% |
0 / 6 |
1892 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 95 |
|
0.00% |
0 / 1 |
1332 | |||
getCacheMode | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
getAllowedParams | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
2 | |||
getExamplesMessages | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
getHelpUrls | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com" |
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 | */ |
22 | |
23 | use MediaWiki\Languages\LanguageFactory; |
24 | use MediaWiki\Languages\LanguageNameUtils; |
25 | use MediaWiki\Pager\AllMessagesTablePager; |
26 | use MediaWiki\Title\Title; |
27 | use Wikimedia\ParamValidator\ParamValidator; |
28 | |
29 | /** |
30 | * A query action to return messages from site message cache |
31 | * |
32 | * @ingroup API |
33 | */ |
34 | class ApiQueryAllMessages extends ApiQueryBase { |
35 | |
36 | private Language $contentLanguage; |
37 | private LanguageFactory $languageFactory; |
38 | private LanguageNameUtils $languageNameUtils; |
39 | private LocalisationCache $localisationCache; |
40 | private MessageCache $messageCache; |
41 | |
42 | /** |
43 | * @param ApiQuery $query |
44 | * @param string $moduleName |
45 | * @param Language $contentLanguage |
46 | * @param LanguageFactory $languageFactory |
47 | * @param LanguageNameUtils $languageNameUtils |
48 | * @param LocalisationCache $localisationCache |
49 | * @param MessageCache $messageCache |
50 | */ |
51 | public function __construct( |
52 | ApiQuery $query, |
53 | $moduleName, |
54 | Language $contentLanguage, |
55 | LanguageFactory $languageFactory, |
56 | LanguageNameUtils $languageNameUtils, |
57 | LocalisationCache $localisationCache, |
58 | MessageCache $messageCache |
59 | ) { |
60 | parent::__construct( $query, $moduleName, 'am' ); |
61 | $this->contentLanguage = $contentLanguage; |
62 | $this->languageFactory = $languageFactory; |
63 | $this->languageNameUtils = $languageNameUtils; |
64 | $this->localisationCache = $localisationCache; |
65 | $this->messageCache = $messageCache; |
66 | } |
67 | |
68 | public function execute() { |
69 | $params = $this->extractRequestParams(); |
70 | if ( $params['lang'] === null ) { |
71 | $langObj = $this->getLanguage(); |
72 | } elseif ( !$this->languageNameUtils->isValidCode( $params['lang'] ) ) { |
73 | $this->dieWithError( |
74 | [ 'apierror-invalidlang', $this->encodeParamName( 'lang' ) ], 'invalidlang' |
75 | ); |
76 | } else { |
77 | $langObj = $this->languageFactory->getLanguage( $params['lang'] ); |
78 | } |
79 | |
80 | if ( $params['enableparser'] ) { |
81 | if ( $params['title'] !== null ) { |
82 | $title = Title::newFromText( $params['title'] ); |
83 | if ( !$title || $title->isExternal() ) { |
84 | $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] ); |
85 | } |
86 | } else { |
87 | $title = Title::newFromText( 'API' ); |
88 | } |
89 | } |
90 | |
91 | $prop = array_fill_keys( (array)$params['prop'], true ); |
92 | |
93 | // Determine which messages should we print |
94 | if ( in_array( '*', $params['messages'] ) ) { |
95 | $message_names = $this->localisationCache->getSubitemList( $langObj->getCode(), 'messages' ) ?? []; |
96 | if ( $params['includelocal'] ) { |
97 | $message_names = array_unique( array_merge( |
98 | $message_names, |
99 | // Pass in the content language code so we get local messages that have a |
100 | // MediaWiki:msgkey page. We might theoretically miss messages that have no |
101 | // MediaWiki:msgkey page but do have a MediaWiki:msgkey/lang page, but that's |
102 | // just a stupid case. |
103 | $this->messageCache->getAllMessageKeys( $this->contentLanguage->getCode() ) |
104 | ) ); |
105 | } |
106 | sort( $message_names ); |
107 | $messages_target = $message_names; |
108 | } else { |
109 | $messages_target = $params['messages']; |
110 | } |
111 | |
112 | // Filter messages that have the specified prefix |
113 | // Because we sorted the message array earlier, they will appear in a clump: |
114 | if ( isset( $params['prefix'] ) ) { |
115 | $skip = false; |
116 | $messages_filtered = []; |
117 | foreach ( $messages_target as $message ) { |
118 | if ( str_starts_with( $message, $params['prefix'] ) ) { |
119 | if ( !$skip ) { |
120 | $skip = true; |
121 | } |
122 | $messages_filtered[] = $message; |
123 | } elseif ( $skip ) { |
124 | break; |
125 | } |
126 | } |
127 | $messages_target = $messages_filtered; |
128 | } |
129 | |
130 | // Filter messages that contain specified string |
131 | if ( isset( $params['filter'] ) ) { |
132 | $messages_filtered = []; |
133 | foreach ( $messages_target as $message ) { |
134 | if ( str_contains( $message, $params['filter'] ) ) { |
135 | $messages_filtered[] = $message; |
136 | } |
137 | } |
138 | $messages_target = $messages_filtered; |
139 | } |
140 | |
141 | // Whether we have any sort of message customisation filtering |
142 | $customiseFilterEnabled = $params['customised'] !== 'all'; |
143 | if ( $customiseFilterEnabled ) { |
144 | $customisedMessages = AllMessagesTablePager::getCustomisedStatuses( |
145 | array_map( |
146 | [ $langObj, 'ucfirst' ], |
147 | $messages_target |
148 | ), |
149 | $langObj->getCode(), |
150 | !$langObj->equals( $this->contentLanguage ), |
151 | $this->getDB() |
152 | ); |
153 | |
154 | $customised = $params['customised'] === 'modified'; |
155 | } |
156 | |
157 | // Get all requested messages and print the result |
158 | $skip = $params['from'] !== null; |
159 | $useto = $params['to'] !== null; |
160 | $result = $this->getResult(); |
161 | foreach ( $messages_target as $message ) { |
162 | // Skip all messages up to $params['from'] |
163 | if ( $skip && $message === $params['from'] ) { |
164 | $skip = false; |
165 | } |
166 | |
167 | if ( $useto && $message > $params['to'] ) { |
168 | break; |
169 | } |
170 | |
171 | if ( !$skip ) { |
172 | $a = [ |
173 | 'name' => $message, |
174 | 'normalizedname' => MessageCache::normalizeKey( $message ), |
175 | ]; |
176 | |
177 | $args = []; |
178 | if ( isset( $params['args'] ) && count( $params['args'] ) != 0 ) { |
179 | $args = $params['args']; |
180 | } |
181 | |
182 | if ( $customiseFilterEnabled ) { |
183 | $messageIsCustomised = isset( $customisedMessages['pages'][$langObj->ucfirst( $message )] ); |
184 | // @phan-suppress-next-line PhanPossiblyUndeclaredVariable customised is set when used |
185 | if ( $customised === $messageIsCustomised ) { |
186 | // @phan-suppress-next-line PhanPossiblyUndeclaredVariable customised is set when used |
187 | if ( $customised ) { |
188 | $a['customised'] = true; |
189 | } |
190 | } else { |
191 | continue; |
192 | } |
193 | } |
194 | |
195 | $msg = $this->msg( $message, $args )->inLanguage( $langObj ); |
196 | |
197 | if ( !$msg->exists() ) { |
198 | $a['missing'] = true; |
199 | } else { |
200 | // Check if the parser is enabled: |
201 | if ( $params['enableparser'] ) { |
202 | // @phan-suppress-next-line PhanPossiblyUndeclaredVariable title is set when used |
203 | $msgString = $msg->page( $title )->text(); |
204 | } else { |
205 | $msgString = $msg->plain(); |
206 | } |
207 | if ( !$params['nocontent'] ) { |
208 | ApiResult::setContentValue( $a, 'content', $msgString ); |
209 | } |
210 | if ( isset( $prop['default'] ) ) { |
211 | $default = $this->msg( $message )->inLanguage( $langObj )->useDatabase( false ); |
212 | if ( !$default->exists() ) { |
213 | $a['defaultmissing'] = true; |
214 | } elseif ( $default->plain() != $msgString ) { |
215 | $a['default'] = $default->plain(); |
216 | } |
217 | } |
218 | } |
219 | $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $a ); |
220 | if ( !$fit ) { |
221 | $this->setContinueEnumParameter( 'from', $message ); |
222 | break; |
223 | } |
224 | } |
225 | } |
226 | $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'message' ); |
227 | } |
228 | |
229 | public function getCacheMode( $params ) { |
230 | if ( $params['lang'] === null ) { |
231 | // Language not specified, will be fetched from preferences |
232 | return 'anon-public-user-private'; |
233 | } elseif ( $params['enableparser'] ) { |
234 | // User-specific parser options will be used |
235 | return 'anon-public-user-private'; |
236 | } else { |
237 | // OK to cache |
238 | return 'public'; |
239 | } |
240 | } |
241 | |
242 | public function getAllowedParams() { |
243 | return [ |
244 | 'messages' => [ |
245 | ParamValidator::PARAM_DEFAULT => '*', |
246 | ParamValidator::PARAM_ISMULTI => true, |
247 | ], |
248 | 'prop' => [ |
249 | ParamValidator::PARAM_ISMULTI => true, |
250 | ParamValidator::PARAM_TYPE => [ |
251 | 'default' |
252 | ] |
253 | ], |
254 | 'enableparser' => false, |
255 | 'nocontent' => false, |
256 | 'includelocal' => false, |
257 | 'args' => [ |
258 | ParamValidator::PARAM_ISMULTI => true, |
259 | ParamValidator::PARAM_ALLOW_DUPLICATES => true, |
260 | ], |
261 | 'filter' => [], |
262 | 'customised' => [ |
263 | ParamValidator::PARAM_DEFAULT => 'all', |
264 | ParamValidator::PARAM_TYPE => [ |
265 | 'all', |
266 | 'modified', |
267 | 'unmodified' |
268 | ] |
269 | ], |
270 | 'lang' => null, |
271 | 'from' => null, |
272 | 'to' => null, |
273 | 'title' => null, |
274 | 'prefix' => null, |
275 | ]; |
276 | } |
277 | |
278 | protected function getExamplesMessages() { |
279 | return [ |
280 | 'action=query&meta=allmessages&refix=ipb-' |
281 | => 'apihelp-query+allmessages-example-ipb', |
282 | 'action=query&meta=allmessages&ammessages=august|mainpage&amlang=de' |
283 | => 'apihelp-query+allmessages-example-de', |
284 | ]; |
285 | } |
286 | |
287 | public function getHelpUrls() { |
288 | return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allmessages'; |
289 | } |
290 | } |