MediaWiki master
ApiParamInfo.php
Go to the documentation of this file.
1<?php
23namespace MediaWiki\Api;
24
32
36class ApiParamInfo extends ApiBase {
37
39 private $helpFormat;
40
42 private $context;
43
45 private $userFactory;
46
47 public function __construct(
48 ApiMain $main,
49 string $action,
50 UserFactory $userFactory
51 ) {
52 parent::__construct( $main, $action );
53 $this->userFactory = $userFactory;
54 }
55
56 public function execute() {
57 // Get parameters
59
60 $this->helpFormat = $params['helpformat'];
61 $this->context = new RequestContext;
62 $this->context->setUser( $this->userFactory->newAnonymous() ); // anon to avoid caching issues
63 $this->context->setLanguage( $this->getMain()->getLanguage() );
64
65 if ( is_array( $params['modules'] ) ) {
66 $modules = [];
67 foreach ( $params['modules'] as $path ) {
68 if ( $path === '*' || $path === '**' ) {
69 $path = "main+$path";
70 }
71 if ( str_ends_with( $path, '+*' ) || str_ends_with( $path, ' *' ) ) {
72 $submodules = true;
73 $path = substr( $path, 0, -2 );
74 $recursive = false;
75 } elseif ( str_ends_with( $path, '+**' ) || str_ends_with( $path, ' **' ) ) {
76 $submodules = true;
77 $path = substr( $path, 0, -3 );
78 $recursive = true;
79 } else {
80 $submodules = false;
81 }
82
83 if ( $submodules ) {
84 try {
85 $module = $this->getModuleFromPath( $path );
86 } catch ( ApiUsageException $ex ) {
87 foreach ( $ex->getStatusValue()->getMessages() as $error ) {
88 $this->addWarning( $error );
89 }
90 continue;
91 }
92 // @phan-suppress-next-next-line PhanTypeMismatchArgumentNullable,PhanPossiblyUndeclaredVariable
93 // recursive is set when used
94 $submodules = $this->listAllSubmodules( $module, $recursive );
95 if ( $submodules ) {
96 $modules = array_merge( $modules, $submodules );
97 } else {
98 $this->addWarning( [ 'apierror-badmodule-nosubmodules', $path ], 'badmodule' );
99 }
100 } else {
101 $modules[] = $path;
102 }
103 }
104 } else {
105 $modules = [];
106 }
107
108 if ( is_array( $params['querymodules'] ) ) {
109 $queryModules = $params['querymodules'];
110 foreach ( $queryModules as $m ) {
111 $modules[] = 'query+' . $m;
112 }
113 } else {
114 $queryModules = [];
115 }
116
117 if ( is_array( $params['formatmodules'] ) ) {
118 $formatModules = $params['formatmodules'];
119 foreach ( $formatModules as $m ) {
120 $modules[] = $m;
121 }
122 } else {
123 $formatModules = [];
124 }
125
126 $modules = array_unique( $modules );
127
128 $res = [];
129
130 foreach ( $modules as $m ) {
131 try {
132 $module = $this->getModuleFromPath( $m );
133 } catch ( ApiUsageException $ex ) {
134 foreach ( $ex->getStatusValue()->getMessages() as $error ) {
135 $this->addWarning( $error );
136 }
137 continue;
138 }
139 $key = 'modules';
140
141 // Back compat
142 $isBCQuery = false;
143 if ( $module->getParent() && $module->getParent()->getModuleName() == 'query' &&
144 in_array( $module->getModuleName(), $queryModules )
145 ) {
146 $isBCQuery = true;
147 $key = 'querymodules';
148 }
149 if ( in_array( $module->getModuleName(), $formatModules ) ) {
150 $key = 'formatmodules';
151 }
152
153 $item = $this->getModuleInfo( $module );
154 if ( $isBCQuery ) {
155 $item['querytype'] = $item['group'];
156 }
157 $res[$key][] = $item;
158 }
159
160 $result = $this->getResult();
161 $result->addValue( [ $this->getModuleName() ], 'helpformat', $this->helpFormat );
162
163 foreach ( $res as $key => $stuff ) {
164 ApiResult::setIndexedTagName( $res[$key], 'module' );
165 }
166
167 if ( $params['mainmodule'] ) {
168 $res['mainmodule'] = $this->getModuleInfo( $this->getMain() );
169 }
170
171 if ( $params['pagesetmodule'] ) {
172 $pageSet = new ApiPageSet( $this->getMain()->getModuleManager()->getModule( 'query' ) );
173 $res['pagesetmodule'] = $this->getModuleInfo( $pageSet );
174 unset( $res['pagesetmodule']['name'] );
175 unset( $res['pagesetmodule']['path'] );
176 unset( $res['pagesetmodule']['group'] );
177 }
178
179 $result->addValue( null, $this->getModuleName(), $res );
180 }
181
188 private function listAllSubmodules( ApiBase $module, $recursive ) {
189 $paths = [];
190 $manager = $module->getModuleManager();
191 if ( $manager ) {
192 $names = $manager->getNames();
193 sort( $names );
194 foreach ( $names as $name ) {
195 $submodule = $manager->getModule( $name );
196 $paths[] = $submodule->getModulePath();
197 if ( $recursive && $submodule->getModuleManager() ) {
198 $paths = array_merge( $paths, $this->listAllSubmodules( $submodule, $recursive ) );
199 }
200 }
201 }
202 return $paths;
203 }
204
211 protected function formatHelpMessages( array &$res, $key, array $msgs, $joinLists = false ) {
212 switch ( $this->helpFormat ) {
213 case 'none':
214 break;
215
216 case 'wikitext':
217 $ret = [];
218 foreach ( $msgs as $m ) {
219 $ret[] = $m->setContext( $this->context )->text();
220 }
221 $res[$key] = implode( "\n\n", $ret );
222 if ( $joinLists ) {
223 $res[$key] = preg_replace( '!^(([*#:;])[^\n]*)\n\n(?=\2)!m', "$1\n", $res[$key] );
224 }
225 break;
226
227 case 'html':
228 $ret = [];
229 foreach ( $msgs as $m ) {
230 $ret[] = $m->setContext( $this->context )->parseAsBlock();
231 }
232 $ret = implode( "\n", $ret );
233 if ( $joinLists ) {
234 $ret = preg_replace( '!\s*</([oud]l)>\s*<\1>\s*!', "\n", $ret );
235 }
236 $res[$key] = Parser::stripOuterParagraph( $ret );
237 break;
238
239 case 'raw':
240 $res[$key] = [];
241 foreach ( $msgs as $m ) {
242 $a = [
243 'key' => $m->getKey(),
244 'params' => $m->getParams(),
245 ];
246 ApiResult::setIndexedTagName( $a['params'], 'param' );
247 if ( $m instanceof ApiHelpParamValueMessage ) {
248 $a['forvalue'] = $m->getParamValue();
249 }
250 $res[$key][] = $a;
251 }
252 ApiResult::setIndexedTagName( $res[$key], 'msg' );
253 break;
254 }
255 }
256
261 private function getModuleInfo( $module ) {
262 $ret = [];
263 $path = $module->getModulePath();
264 $paramValidator = $module->getMain()->getParamValidator();
265
266 $ret['name'] = $module->getModuleName();
267 $ret['classname'] = get_class( $module );
268 $ret['path'] = $path;
269 if ( !$module->isMain() ) {
270 $ret['group'] = $module->getParent()->getModuleManager()->getModuleGroup(
271 $module->getModuleName()
272 );
273 }
274 $ret['prefix'] = $module->getModulePrefix();
275
276 $sourceInfo = $module->getModuleSourceInfo();
277 if ( $sourceInfo ) {
278 $ret['source'] = $sourceInfo['name'];
279 if ( isset( $sourceInfo['namemsg'] ) ) {
280 $ret['sourcename'] = $this->context->msg( $sourceInfo['namemsg'] )->text();
281 } else {
282 $ret['sourcename'] = $ret['source'];
283 }
284
285 $link = SpecialPage::getTitleFor( 'Version', 'License/' . $sourceInfo['name'] )->getFullURL();
286 if ( isset( $sourceInfo['license-name'] ) ) {
287 $ret['licensetag'] = $sourceInfo['license-name'];
288 $ret['licenselink'] = (string)$link;
289 } elseif ( ExtensionInfo::getLicenseFileNames( dirname( $sourceInfo['path'] ) ) ) {
290 $ret['licenselink'] = (string)$link;
291 }
292 }
293
294 $this->formatHelpMessages( $ret, 'description', $module->getFinalDescription() );
295
296 foreach ( $module->getHelpFlags() as $flag ) {
297 $ret[$flag] = true;
298 }
299
300 $ret['helpurls'] = (array)$module->getHelpUrls();
301 if ( isset( $ret['helpurls'][0] ) && $ret['helpurls'][0] === false ) {
302 $ret['helpurls'] = [];
303 }
304 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset False positive
305 ApiResult::setIndexedTagName( $ret['helpurls'], 'helpurl' );
306
307 if ( $this->helpFormat !== 'none' ) {
308 $ret['examples'] = [];
309 $examples = $module->getExamplesMessages();
310 foreach ( $examples as $qs => $msg ) {
311 $item = [
312 'query' => $qs
313 ];
314 $msg = $this->msg(
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'] = [];
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 = $this->msg(
406 Message::newFromSpecifier( $dynamicParams ),
407 $module->getModulePrefix(),
408 $module->getModuleName(),
409 $module->getModulePath()
410 );
411 $this->formatHelpMessages( $ret, 'dynamicparameters', [ $dynamicParams ] );
412 }
413 }
414
415 return $ret;
416 }
417
418 public function isReadMode() {
419 return false;
420 }
421
422 public function getAllowedParams() {
423 // back compat
424 $querymodules = $this->getMain()->getModuleManager()
425 ->getModule( 'query' )->getModuleManager()->getNames();
426 sort( $querymodules );
427 $formatmodules = $this->getMain()->getModuleManager()->getNames( 'format' );
428 sort( $formatmodules );
429
430 return [
431 'modules' => [
432 ParamValidator::PARAM_ISMULTI => true,
433 ],
434 'helpformat' => [
435 ParamValidator::PARAM_DEFAULT => 'none',
436 ParamValidator::PARAM_TYPE => [ 'html', 'wikitext', 'raw', 'none' ],
437 ],
438
439 'querymodules' => [
440 ParamValidator::PARAM_DEPRECATED => true,
441 ParamValidator::PARAM_ISMULTI => true,
442 ParamValidator::PARAM_TYPE => $querymodules,
443 ],
444 'mainmodule' => [
445 ParamValidator::PARAM_DEPRECATED => true,
446 ],
447 'pagesetmodule' => [
448 ParamValidator::PARAM_DEPRECATED => true,
449 ],
450 'formatmodules' => [
451 ParamValidator::PARAM_DEPRECATED => true,
452 ParamValidator::PARAM_ISMULTI => true,
453 ParamValidator::PARAM_TYPE => $formatmodules,
454 ]
455 ];
456 }
457
458 protected function getExamplesMessages() {
459 return [
460 'action=paraminfo&modules=parse|phpfm|query%2Ballpages|query%2Bsiteinfo'
461 => 'apihelp-paraminfo-example-1',
462 'action=paraminfo&modules=query%2B*'
463 => 'apihelp-paraminfo-example-2',
464 ];
465 }
466
467 public function getHelpUrls() {
468 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parameter_information';
469 }
470}
471
473class_alias( ApiParamInfo::class, 'ApiParamInfo' );
array $params
The job parameters.
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:76
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition ApiBase.php:2130
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition ApiBase.php:580
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:571
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition ApiBase.php:202
getMain()
Get the main module.
Definition ApiBase.php:589
getModulePath()
Get the path to this module.
Definition ApiBase.php:650
getHelpUrls()
Return links to more detailed help pages about the module.
Definition ApiBase.php:397
getModuleManager()
Get the module manager, or null if this module has no submodules.
Definition ApiBase.php:354
getResult()
Get the result object.
Definition ApiBase.php:710
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1495
getFinalDescription()
Get the final module description, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1931
getParent()
Get the parent of this module.
Definition ApiBase.php:610
const PARAM_TEMPLATE_VARS
(array) Indicate that this is a templated parameter, and specify replacements.
Definition ApiBase.php:242
getExamplesMessages()
Returns usage examples for this module.
Definition ApiBase.php:386
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:851
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1998
getFinalParams( $flags=0)
Get the final list of parameters, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1967
needsToken()
Returns the token type this module requires in order to execute.
Definition ApiBase.php:525
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition ApiBase.php:817
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition ApiBase.php:2163
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition ApiBase.php:599
getModuleFromPath( $path)
Get a module from its module path.
Definition ApiBase.php:670
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When this is set, the result could take longer to generate,...
Definition ApiBase.php:262
Message subclass that prepends wikitext for API help.
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:78
This class contains a list of pages that the client has requested.
getHelpUrls()
Return links to more detailed help pages about the module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
__construct(ApiMain $main, string $action, UserFactory $userFactory)
formatHelpMessages(array &$res, $key, array $msgs, $joinLists=false)
getExamplesMessages()
Returns usage examples for this module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
isReadMode()
Indicates whether this module requires read rights.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
static setSubelementsList(array &$arr, $names)
Causes the elements with the specified names to be output as subelements rather than attributes.
Exception used to abort API execution with an error.
getStatusValue()
Fetch the error status.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Group all the pieces relevant to the context of a request into one instance.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:155
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Definition Message.php:471
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:145
Parent class for all special pages.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Creates User objects.
Service for formatting and validating API parameters.