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