MediaWiki master
ApiParamInfo.php
Go to the documentation of this file.
1<?php
29
33class ApiParamInfo extends ApiBase {
34
35 private $helpFormat;
36
38 private $context;
39
41 private $userFactory;
42
48 public function __construct(
49 ApiMain $main,
50 $action,
51 UserFactory $userFactory
52 ) {
53 parent::__construct( $main, $action );
54 $this->userFactory = $userFactory;
55 }
56
57 public function execute() {
58 // Get parameters
60
61 $this->helpFormat = $params['helpformat'];
62 $this->context = new RequestContext;
63 $this->context->setUser( $this->userFactory->newAnonymous() ); // anon to avoid caching issues
64 $this->context->setLanguage( $this->getMain()->getLanguage() );
65
66 if ( is_array( $params['modules'] ) ) {
67 $modules = [];
68 foreach ( $params['modules'] as $path ) {
69 if ( $path === '*' || $path === '**' ) {
70 $path = "main+$path";
71 }
72 if ( str_ends_with( $path, '+*' ) || str_ends_with( $path, ' *' ) ) {
73 $submodules = true;
74 $path = substr( $path, 0, -2 );
75 $recursive = false;
76 } elseif ( str_ends_with( $path, '+**' ) || str_ends_with( $path, ' **' ) ) {
77 $submodules = true;
78 $path = substr( $path, 0, -3 );
79 $recursive = true;
80 } else {
81 $submodules = false;
82 }
83
84 if ( $submodules ) {
85 try {
86 $module = $this->getModuleFromPath( $path );
87 } catch ( ApiUsageException $ex ) {
88 foreach ( $ex->getStatusValue()->getErrors() as $error ) {
89 $this->addWarning( $error );
90 }
91 continue;
92 }
93 // @phan-suppress-next-next-line PhanTypeMismatchArgumentNullable,PhanPossiblyUndeclaredVariable
94 // recursive is set when used
95 $submodules = $this->listAllSubmodules( $module, $recursive );
96 if ( $submodules ) {
97 $modules = array_merge( $modules, $submodules );
98 } else {
99 $this->addWarning( [ 'apierror-badmodule-nosubmodules', $path ], 'badmodule' );
100 }
101 } else {
102 $modules[] = $path;
103 }
104 }
105 } else {
106 $modules = [];
107 }
108
109 if ( is_array( $params['querymodules'] ) ) {
110 $queryModules = $params['querymodules'];
111 foreach ( $queryModules as $m ) {
112 $modules[] = 'query+' . $m;
113 }
114 } else {
115 $queryModules = [];
116 }
117
118 if ( is_array( $params['formatmodules'] ) ) {
119 $formatModules = $params['formatmodules'];
120 foreach ( $formatModules as $m ) {
121 $modules[] = $m;
122 }
123 } else {
124 $formatModules = [];
125 }
126
127 $modules = array_unique( $modules );
128
129 $res = [];
130
131 foreach ( $modules as $m ) {
132 try {
133 $module = $this->getModuleFromPath( $m );
134 } catch ( ApiUsageException $ex ) {
135 foreach ( $ex->getStatusValue()->getErrors() as $error ) {
136 $this->addWarning( $error );
137 }
138 continue;
139 }
140 $key = 'modules';
141
142 // Back compat
143 $isBCQuery = false;
144 if ( $module->getParent() && $module->getParent()->getModuleName() == 'query' &&
145 in_array( $module->getModuleName(), $queryModules )
146 ) {
147 $isBCQuery = true;
148 $key = 'querymodules';
149 }
150 if ( in_array( $module->getModuleName(), $formatModules ) ) {
151 $key = 'formatmodules';
152 }
153
154 $item = $this->getModuleInfo( $module );
155 if ( $isBCQuery ) {
156 $item['querytype'] = $item['group'];
157 }
158 $res[$key][] = $item;
159 }
160
161 $result = $this->getResult();
162 $result->addValue( [ $this->getModuleName() ], 'helpformat', $this->helpFormat );
163
164 foreach ( $res as $key => $stuff ) {
165 ApiResult::setIndexedTagName( $res[$key], 'module' );
166 }
167
168 if ( $params['mainmodule'] ) {
169 $res['mainmodule'] = $this->getModuleInfo( $this->getMain() );
170 }
171
172 if ( $params['pagesetmodule'] ) {
173 $pageSet = new ApiPageSet( $this->getMain()->getModuleManager()->getModule( 'query' ) );
174 $res['pagesetmodule'] = $this->getModuleInfo( $pageSet );
175 unset( $res['pagesetmodule']['name'] );
176 unset( $res['pagesetmodule']['path'] );
177 unset( $res['pagesetmodule']['group'] );
178 }
179
180 $result->addValue( null, $this->getModuleName(), $res );
181 }
182
189 private function listAllSubmodules( ApiBase $module, $recursive ) {
190 $paths = [];
191 $manager = $module->getModuleManager();
192 if ( $manager ) {
193 $names = $manager->getNames();
194 sort( $names );
195 foreach ( $names as $name ) {
196 $submodule = $manager->getModule( $name );
197 $paths[] = $submodule->getModulePath();
198 if ( $recursive && $submodule->getModuleManager() ) {
199 $paths = array_merge( $paths, $this->listAllSubmodules( $submodule, $recursive ) );
200 }
201 }
202 }
203 return $paths;
204 }
205
212 protected function formatHelpMessages( array &$res, $key, array $msgs, $joinLists = false ) {
213 switch ( $this->helpFormat ) {
214 case 'none':
215 break;
216
217 case 'wikitext':
218 $ret = [];
219 foreach ( $msgs as $m ) {
220 $ret[] = $m->setContext( $this->context )->text();
221 }
222 $res[$key] = implode( "\n\n", $ret );
223 if ( $joinLists ) {
224 $res[$key] = preg_replace( '!^(([*#:;])[^\n]*)\n\n(?=\2)!m', "$1\n", $res[$key] );
225 }
226 break;
227
228 case 'html':
229 $ret = [];
230 foreach ( $msgs as $m ) {
231 $ret[] = $m->setContext( $this->context )->parseAsBlock();
232 }
233 $ret = implode( "\n", $ret );
234 if ( $joinLists ) {
235 $ret = preg_replace( '!\s*</([oud]l)>\s*<\1>\s*!', "\n", $ret );
236 }
237 $res[$key] = Parser::stripOuterParagraph( $ret );
238 break;
239
240 case 'raw':
241 $res[$key] = [];
242 foreach ( $msgs as $m ) {
243 $a = [
244 'key' => $m->getKey(),
245 'params' => $m->getParams(),
246 ];
247 ApiResult::setIndexedTagName( $a['params'], 'param' );
248 if ( $m instanceof ApiHelpParamValueMessage ) {
249 $a['forvalue'] = $m->getParamValue();
250 }
251 $res[$key][] = $a;
252 }
253 ApiResult::setIndexedTagName( $res[$key], 'msg' );
254 break;
255 }
256 }
257
262 private function getModuleInfo( $module ) {
263 $ret = [];
264 $path = $module->getModulePath();
265 $paramValidator = $module->getMain()->getParamValidator();
266
267 $ret['name'] = $module->getModuleName();
268 $ret['classname'] = get_class( $module );
269 $ret['path'] = $path;
270 if ( !$module->isMain() ) {
271 $ret['group'] = $module->getParent()->getModuleManager()->getModuleGroup(
272 $module->getModuleName()
273 );
274 }
275 $ret['prefix'] = $module->getModulePrefix();
276
277 $sourceInfo = $module->getModuleSourceInfo();
278 if ( $sourceInfo ) {
279 $ret['source'] = $sourceInfo['name'];
280 if ( isset( $sourceInfo['namemsg'] ) ) {
281 $ret['sourcename'] = $this->context->msg( $sourceInfo['namemsg'] )->text();
282 } else {
283 $ret['sourcename'] = $ret['source'];
284 }
285
286 $link = SpecialPage::getTitleFor( 'Version', 'License/' . $sourceInfo['name'] )->getFullURL();
287 if ( isset( $sourceInfo['license-name'] ) ) {
288 $ret['licensetag'] = $sourceInfo['license-name'];
289 $ret['licenselink'] = (string)$link;
290 } elseif ( ExtensionInfo::getLicenseFileNames( dirname( $sourceInfo['path'] ) ) ) {
291 $ret['licenselink'] = (string)$link;
292 }
293 }
294
295 $this->formatHelpMessages( $ret, 'description', $module->getFinalDescription() );
296
297 foreach ( $module->getHelpFlags() as $flag ) {
298 $ret[$flag] = true;
299 }
300
301 $ret['helpurls'] = (array)$module->getHelpUrls();
302 if ( isset( $ret['helpurls'][0] ) && $ret['helpurls'][0] === false ) {
303 $ret['helpurls'] = [];
304 }
305 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset False positive
306 ApiResult::setIndexedTagName( $ret['helpurls'], 'helpurl' );
307
308 if ( $this->helpFormat !== 'none' ) {
309 $ret['examples'] = [];
310 $examples = $module->getExamplesMessages();
311 foreach ( $examples as $qs => $msg ) {
312 $item = [
313 'query' => $qs
314 ];
315 $msg = ApiBase::makeMessage( $msg, $this->context, [
316 $module->getModulePrefix(),
317 $module->getModuleName(),
318 $module->getModulePath()
319 ] );
320 $this->formatHelpMessages( $item, 'description', [ $msg ] );
321 if ( isset( $item['description'] ) ) {
322 if ( is_array( $item['description'] ) ) {
323 $item['description'] = $item['description'][0];
324 } else {
325 ApiResult::setSubelementsList( $item, 'description' );
326 }
327 }
328 $ret['examples'][] = $item;
329 }
330 ApiResult::setIndexedTagName( $ret['examples'], 'example' );
331 }
332
333 $ret['parameters'] = [];
334 $ret['templatedparameters'] = [];
335 $params = $module->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
336 $paramDesc = $module->getFinalParamDescription();
337 $index = 0;
338 foreach ( $params as $name => $settings ) {
339 $settings = $paramValidator->normalizeSettings( $settings );
340
341 $item = [
342 'index' => ++$index,
343 'name' => $name,
344 ];
345
346 if ( !empty( $settings[ApiBase::PARAM_TEMPLATE_VARS] ) ) {
347 $item['templatevars'] = $settings[ApiBase::PARAM_TEMPLATE_VARS];
348 ApiResult::setIndexedTagName( $item['templatevars'], 'var' );
349 }
350
351 if ( isset( $paramDesc[$name] ) ) {
352 $this->formatHelpMessages( $item, 'description', $paramDesc[$name], true );
353 }
354
355 foreach ( $paramValidator->getParamInfo( $module, $name, $settings, [] ) as $k => $v ) {
356 $item[$k] = $v;
357 }
358
359 if ( $name === 'token' && $module->needsToken() ) {
360 $item['tokentype'] = $module->needsToken();
361 }
362
363 if ( $item['type'] === 'NULL' ) {
364 // Munge "NULL" to "string" for historical reasons
365 $item['type'] = 'string';
366 } elseif ( is_array( $item['type'] ) ) {
367 // Set indexed tag name, for historical reasons
368 ApiResult::setIndexedTagName( $item['type'], 't' );
369 }
370
371 if ( !empty( $settings[ApiBase::PARAM_HELP_MSG_INFO] ) ) {
372 $item['info'] = [];
373 foreach ( $settings[ApiBase::PARAM_HELP_MSG_INFO] as $i ) {
374 $tag = array_shift( $i );
375 $info = [
376 'name' => $tag,
377 ];
378 if ( count( $i ) ) {
379 $info['values'] = $i;
380 ApiResult::setIndexedTagName( $info['values'], 'v' );
381 }
382 $this->formatHelpMessages( $info, 'text', [
383 $this->context->msg( "apihelp-{$path}-paraminfo-{$tag}" )
384 ->numParams( count( $i ) )
385 ->params( $this->context->getLanguage()->commaList( $i ) )
386 ->params( $module->getModulePrefix() )
387 ] );
388 ApiResult::setSubelementsList( $info, 'text' );
389 $item['info'][] = $info;
390 }
391 ApiResult::setIndexedTagName( $item['info'], 'i' );
392 }
393
394 $key = empty( $settings[ApiBase::PARAM_TEMPLATE_VARS] ) ? 'parameters' : 'templatedparameters';
395 $ret[$key][] = $item;
396 }
397 ApiResult::setIndexedTagName( $ret['parameters'], 'param' );
398 ApiResult::setIndexedTagName( $ret['templatedparameters'], 'param' );
399
400 $dynamicParams = $module->dynamicParameterDocumentation();
401 if ( $dynamicParams !== null ) {
402 if ( $this->helpFormat === 'none' ) {
403 $ret['dynamicparameters'] = true;
404 } else {
405 $dynamicParams = ApiBase::makeMessage( $dynamicParams, $this->context, [
406 $module->getModulePrefix(),
407 $module->getModuleName(),
408 $module->getModulePath()
409 ] );
410 $this->formatHelpMessages( $ret, 'dynamicparameters', [ $dynamicParams ] );
411 }
412 }
413
414 return $ret;
415 }
416
417 public function isReadMode() {
418 return false;
419 }
420
421 public function getAllowedParams() {
422 // back compat
423 $querymodules = $this->getMain()->getModuleManager()
424 ->getModule( 'query' )->getModuleManager()->getNames();
425 sort( $querymodules );
426 $formatmodules = $this->getMain()->getModuleManager()->getNames( 'format' );
427 sort( $formatmodules );
428
429 return [
430 'modules' => [
431 ParamValidator::PARAM_ISMULTI => true,
432 ],
433 'helpformat' => [
434 ParamValidator::PARAM_DEFAULT => 'none',
435 ParamValidator::PARAM_TYPE => [ 'html', 'wikitext', 'raw', 'none' ],
436 ],
437
438 'querymodules' => [
439 ParamValidator::PARAM_DEPRECATED => true,
440 ParamValidator::PARAM_ISMULTI => true,
441 ParamValidator::PARAM_TYPE => $querymodules,
442 ],
443 'mainmodule' => [
444 ParamValidator::PARAM_DEPRECATED => true,
445 ],
446 'pagesetmodule' => [
447 ParamValidator::PARAM_DEPRECATED => true,
448 ],
449 'formatmodules' => [
450 ParamValidator::PARAM_DEPRECATED => true,
451 ParamValidator::PARAM_ISMULTI => true,
452 ParamValidator::PARAM_TYPE => $formatmodules,
453 ]
454 ];
455 }
456
457 protected function getExamplesMessages() {
458 return [
459 'action=paraminfo&modules=parse|phpfm|query%2Ballpages|query%2Bsiteinfo'
460 => 'apihelp-paraminfo-example-1',
461 'action=paraminfo&modules=query%2B*'
462 => 'apihelp-paraminfo-example-2',
463 ];
464 }
465
466 public function getHelpUrls() {
467 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parameter_information';
468 }
469}
array $params
The job parameters.
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:64
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition ApiBase.php:550
getModuleFromPath( $path)
Get a module from its module path.
Definition ApiBase.php:640
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
Definition ApiBase.php:1294
getParent()
Get the parent of this module.
Definition ApiBase.php:580
getHelpUrls()
Return links to more detailed help pages about the module.
Definition ApiBase.php:383
getModuleManager()
Get the module manager, or null if this module has no submodules.
Definition ApiBase.php:340
getMain()
Get the main module.
Definition ApiBase.php:559
getExamplesMessages()
Returns usage examples for this module.
Definition ApiBase.php:372
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition ApiBase.php:2127
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition ApiBase.php:569
getFinalDescription()
Get the final module description, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1886
const PARAM_TEMPLATE_VARS
(array) Indicate that this is a templated parameter, and specify replacements.
Definition ApiBase.php:229
getResult()
Get the result object.
Definition ApiBase.php:680
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:820
needsToken()
Returns the token type this module requires in order to execute.
Definition ApiBase.php:495
getModulePath()
Get the path to this module.
Definition ApiBase.php:620
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition ApiBase.php:2094
getFinalParams( $flags=0)
Get the final list of parameters, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1915
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1460
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:541
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1946
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition ApiBase.php:786
Message subclass that prepends wikitext for API help.
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:65
This class contains a list of pages that the client has requested.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
isReadMode()
Indicates whether this module requires read rights.
getHelpUrls()
Return links to more detailed help pages about the module.
__construct(ApiMain $main, $action, UserFactory $userFactory)
formatHelpMessages(array &$res, $key, array $msgs, $joinLists=false)
getExamplesMessages()
Returns usage examples for this module.
static setSubelementsList(array &$arr, $names)
Causes the elements with the specified names to be output as subelements rather than attributes.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Exception used to abort API execution with an error.
getStatusValue()
Fetch the error status.
Group all the pieces relevant to the context of a request into one instance.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:156
Parent class for all special pages.
Creates User objects.
Service for formatting and validating API parameters.