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