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