23 use HtmlFormatter\HtmlFormatter;
49 parent::__construct( $main, $action );
57 foreach ( $params[
'modules'] as
$path ) {
63 $context->setSkin( $this->skinFactory->makeSkin(
'apioutput' ) );
67 $out->setRobotPolicy(
'noindex,nofollow' );
68 $out->setCopyrightUrl(
'https://www.mediawiki.org/wiki/Special:MyLanguage/Copyright' );
69 $out->disallowUserJs();
77 $html = ob_get_clean();
80 if ( $params[
'wrap'] ) {
82 'mime' =>
'text/html',
83 'filename' =>
'api-help.html',
91 'Types' => [
'AssocAsObject' =>
true ],
94 $errors = array_filter( [
95 'errors' => $this->
getResult()->getResultData( [
'errors' ], $transform ),
96 'warnings' => $this->
getResult()->getResultData( [
'warnings' ], $transform ),
102 $json = str_replace(
'--',
'-\u002D', $json );
103 $html =
"<!-- API warnings and errors:\n$json\n-->\n$html";
138 $out->addModuleStyles( [
140 'mediawiki.apipretty',
142 $out->setPageTitle(
$context->
msg(
'api-help-title' ) );
144 $services = MediaWikiServices::getInstance();
145 $cache = $services->getMainWANObjectCache();
148 $options[
'recursivesubmodules'] &&
151 $cacheHelpTimeout =
$context->
getConfig()->get( MainConfigNames::APICacheHelpTimeout );
152 if ( $cacheHelpTimeout > 0 ) {
155 (
int)!empty( $options[
'toc'] ),
157 $cached =
$cache->get( $cacheKey );
159 $out->addHTML( $cached );
164 if ( $out->getHTML() !==
'' ) {
170 $options[
'recursivesubmodules'] = !empty( $options[
'recursivesubmodules'] );
171 $options[
'submodules'] = $options[
'recursivesubmodules'] || !empty( $options[
'submodules'] );
174 if ( empty( $options[
'nolead'] ) ) {
176 if ( !$msg->isDisabled() ) {
177 $out->addHTML( $msg->parseAsBlock() );
183 if ( !empty( $options[
'toc'] ) && $haveModules ) {
187 $out->addHTML( $html );
189 $helptitle = $options[
'helptitle'] ??
null;
192 $out->addHTML( $html );
194 if ( $cacheKey !==
null ) {
196 $cache->set( $cacheKey, $out->getHTML(), $cacheHelpTimeout );
208 public static function fixHelpLinks( $html, $helptitle =
null, $localModules = [] ) {
209 $formatter =
new HtmlFormatter( $html );
210 $doc = $formatter->getDoc();
211 $xpath =
new DOMXPath( $doc );
212 $nodes = $xpath->query(
'//a[@href][not(contains(@class,\'apihelp-linktrail\'))]' );
214 foreach ( $nodes as $node ) {
215 $href = $node->getAttribute(
'href' );
218 $href = rawurldecode( $href );
219 }
while ( $old !== $href );
220 if ( preg_match(
'!Special:ApiHelp/([^&/|#]+)((?:#.*)?)!', $href, $m ) ) {
221 if ( isset( $localModules[$m[1]] ) ) {
222 $href = $m[2] ===
'' ?
'#' . $m[1] : $m[2];
223 } elseif ( $helptitle !==
null ) {
232 $node->setAttribute(
'href', $href );
233 $node->removeAttribute(
'title' );
237 return $formatter->getText();
248 private static function wrap(
Message $msg, $class, $tag =
'span' ) {
264 array $options, &$haveModules
268 $level = empty( $options[
'headerlevel'] ) ? 2 : $options[
'headerlevel'];
269 if ( empty( $options[
'tocnumber'] ) ) {
270 $tocnumber = [ 2 => 0 ];
272 $tocnumber = &$options[
'tocnumber'];
276 $paramValidator = $module->getMain()->getParamValidator();
277 $tocnumber[$level]++;
278 $path = $module->getModulePath();
290 if ( empty( $options[
'noheader'] ) || !empty( $options[
'toc'] ) ) {
293 while ( isset( $haveModules[$anchor] ) ) {
294 $anchor =
$path .
'|' . ++$i;
297 if ( $module->isMain() ) {
298 $headerContent =
$context->
msg(
'api-help-main-header' )->parse();
300 'class' =>
'apihelp-header',
303 $name = $module->getModuleName();
304 $headerContent = htmlspecialchars(
305 $module->getParent()->getModuleManager()->getModuleGroup( $name ) .
"=$name"
307 if ( $module->getModulePrefix() !==
'' ) {
308 $headerContent .=
' ' .
309 $context->
msg(
'parentheses', $module->getModulePrefix() )->parse();
315 'class' =>
'apihelp-header apihelp-module-name',
321 $headerAttr[
'id'] = $anchor;
323 $haveModules[$anchor] = [
324 'toclevel' => count( $tocnumber ),
327 'line' => $headerContent,
328 'number' => implode(
'.', $tocnumber ),
331 if ( empty( $options[
'noheader'] ) ) {
333 'h' . min( 6, $level ),
339 $haveModules[
$path] =
true;
344 for ( $m = $module; $m !==
null; $m = $m->getParent() ) {
345 $name = $m->getModuleName();
346 if ( $name ===
'main_int' ) {
351 !( !empty( $options[
'submodules'] ) && $m->getModuleManager() )
353 $link =
Html::element(
'b', [
'dir' =>
'ltr',
'lang' =>
'en' ], $name );
357 [
'href' => $link,
'class' =>
'apihelp-linktrail',
'dir' =>
'ltr',
'lang' =>
'en' ],
362 array_unshift( $links, $link );
368 'apihelp-linktrail',
'div'
372 $flags = $module->getHelpFlags();
374 [
'class' =>
'apihelp-block apihelp-flags' ] );
376 if ( !$msg->isDisabled() ) {
378 $msg->numParams( count( $flags ) ),
'apihelp-block-head',
'div'
382 foreach ( $flags as $flag ) {
390 self::wrap(
$context->
msg(
"api-help-flag-$flag" ),
"apihelp-flag-$flag" )
393 $sourceInfo = $module->getModuleSourceInfo();
395 if ( isset( $sourceInfo[
'namemsg'] ) ) {
396 $extname =
$context->
msg( $sourceInfo[
'namemsg'] )->text();
399 $extname =
Html::element(
'span', [
'dir' =>
'ltr',
'lang' =>
'en' ], $sourceInfo[
'name'] );
403 $context->
msg(
'api-help-source', $extname, $sourceInfo[
'name'] ),
409 if ( isset( $sourceInfo[
'license-name'] ) ) {
411 Html::element(
'span', [
'dir' =>
'ltr',
'lang' =>
'en' ], $sourceInfo[
'license-name'] )
413 } elseif ( ExtensionInfo::getLicenseFileNames( dirname( $sourceInfo[
'path'] ) ) ) {
414 $msg =
$context->
msg(
'api-help-license-noname', $link );
416 $msg =
$context->
msg(
'api-help-license-unknown' );
419 self::wrap( $msg,
'apihelp-license' )
423 self::wrap(
$context->
msg(
'api-help-source-unknown' ),
'apihelp-source' )
426 self::wrap(
$context->
msg(
'api-help-license-unknown' ),
'apihelp-license' )
432 foreach ( $module->getFinalDescription() as $msg ) {
434 $help[
'description'] .= $msg->parseAsBlock();
437 $urls = $module->getHelpUrls();
439 if ( !is_array( $urls ) ) {
443 [
'class' =>
'apihelp-block apihelp-help-urls' ]
446 if ( !$msg->isDisabled() ) {
448 $msg->numParams( count( $urls ) ),
'apihelp-block-head',
'div'
452 foreach ( $urls as $url ) {
454 Html::element(
'a', [
'href' => $url,
'dir' =>
'ltr' ], $url )
462 $dynamicParams = $module->dynamicParameterDocumentation();
464 if ( $params || $dynamicParams !==
null ) {
466 [
'class' =>
'apihelp-block apihelp-parameters' ]
469 if ( !$msg->isDisabled() ) {
471 $msg->numParams( count( $params ) ),
'apihelp-block-head',
'div'
476 $descriptions = $module->getFinalParamDescription();
478 foreach ( $params as $name => $settings ) {
479 $settings = $paramValidator->normalizeSettings( $settings );
486 Html::element(
'span', [
'dir' =>
'ltr',
'lang' =>
'en' ], $module->encodeParamName( $name ) )
491 if ( isset( $descriptions[$name] ) ) {
492 foreach ( $descriptions[$name] as $msg ) {
494 $description[] = $msg->parseAsBlock();
497 if ( !array_filter( $description ) ) {
507 [
'class' =>
'info' ] );
510 'apihelp-deprecated',
'strong'
515 if ( $description ) {
516 $description = implode(
'', $description );
517 $description = preg_replace(
'!\s*</([oud]l)>\s*<\1>\s*!',
"\n", $description );
519 [
'class' =>
'description' ], $description );
524 $paramHelp = $paramValidator->getHelpInfo( $module, $name, $settings, [] );
526 unset( $paramHelp[ParamValidator::PARAM_DEPRECATED] );
528 if ( isset( $paramHelp[ParamValidator::PARAM_REQUIRED] ) ) {
529 $paramHelp[ParamValidator::PARAM_REQUIRED]->setContext(
$context );
530 $info[] = $paramHelp[ParamValidator::PARAM_REQUIRED];
531 unset( $paramHelp[ParamValidator::PARAM_REQUIRED] );
537 $tag = array_shift( $i );
538 $info[] =
$context->
msg(
"apihelp-{$path}-paraminfo-{$tag}" )
539 ->numParams( count( $i ) )
541 ->params( $module->getModulePrefix() )
549 $msg =
'api-help-param-templated-var-first';
551 $vars[] =
$context->
msg( $msg, $k, $module->encodeParamName( $v ) );
552 $msg =
'api-help-param-templated-var';
554 $info[] =
$context->
msg(
'api-help-param-templated' )
555 ->numParams( count( $vars ) )
561 foreach ( $paramHelp as $m ) {
566 foreach ( $info as $i ) {
571 if ( $dynamicParams !==
null ) {
573 $module->getModulePrefix(),
574 $module->getModuleName(),
575 $module->getModulePath()
579 [
'class' =>
'description' ], $dynamicParams->parse() );
586 $examples = $module->getExamplesMessages();
589 [
'class' =>
'apihelp-block apihelp-examples' ] );
591 if ( !$msg->isDisabled() ) {
593 $msg->numParams( count( $examples ) ),
'apihelp-block-head',
'div'
598 foreach ( $examples as $qs => $msg ) {
600 $module->getModulePrefix(),
601 $module->getModuleName(),
602 $module->getModulePath()
609 Html::element(
'a', [
'href' => $link,
'dir' =>
'ltr' ],
"api.php?$qs" ) .
' ' .
611 $context->
msg(
'api-help-open-in-apisandbox' )->parse() )
618 $subtocnumber = $tocnumber;
619 $subtocnumber[$level + 1] = 0;
621 'submodules' => $options[
'recursivesubmodules'],
622 'headerlevel' => $level + 1,
623 'tocnumber' => &$subtocnumber,
628 if ( $options[
'submodules'] && $module->getModuleManager() ) {
629 $manager = $module->getModuleManager();
631 foreach ( $groups as $group ) {
632 $names = $manager->getNames( $group );
634 foreach ( $names as $name ) {
635 $submodules[] = $manager->getModule( $name );
646 $module->modifyHelp(
$help, $suboptions, $haveModules );
648 $module->getHookRunner()->onAPIHelpModifyOutput( $module,
$help,
649 $suboptions, $haveModules );
651 $out .= implode(
"\n",
$help );
667 if ( $params[
'wrap'] ) {
672 $errorPrinter = $main->createPrinterByName( $main->getParameter(
'format' ) );
682 'submodules' =>
false,
683 'recursivesubmodules' =>
false,
692 =>
'apihelp-help-example-main',
693 'action=help&modules=query&submodules=1'
694 =>
'apihelp-help-example-submodules',
695 'action=help&recursivesubmodules=1'
696 =>
'apihelp-help-example-recursive',
697 'action=help&modules=help'
698 =>
'apihelp-help-example-help',
699 'action=help&modules=query+info|query+categorymembers'
700 =>
'apihelp-help-example-query',
706 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Main_page',
707 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:FAQ',
708 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Quick_start_guide',
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
This abstract class implements many basic API functions, and is the base of all API classes.
getModuleFromPath( $path)
Get a module from its module path.
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
getMain()
Get the main module.
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
const PARAM_TEMPLATE_VARS
(array) Indicate that this is a templated parameter, and specify replacements.
getResult()
Get the result object.
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
getModulePath()
Get the path to this module.
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When set, the result could take longer to generate, but should be more thoro...
getModuleName()
Get the name of the module being executed by this instance.
Class to output help for an API module.
static wrap(Message $msg, $class, $tag='span')
Wrap a message in HTML with a class.
isReadMode()
Indicates whether this module requires read rights.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getExamplesMessages()
Returns usage examples for this module.
static fixHelpLinks( $html, $helptitle=null, $localModules=[])
Replace Special:ApiHelp links with links to api.php.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getHelpUrls()
Return links to more detailed help pages about the module.
static getHelpInternal(IContextSource $context, array $modules, array $options, &$haveModules)
Recursively-called function to actually construct the help.
static getHelp(IContextSource $context, $modules, array $options)
Generate help for the specified modules.
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
__construct(ApiMain $main, $action, SkinFactory $skinFactory)
getCustomPrinter()
If the module may only be used with a certain format module, it should override this method to return...
This is the main API class, used for both external and internal processing.
const NO_SIZE_CHECK
For addValue() and similar functions, do not check size while adding a value Don't use this unless yo...
static setSubelementsList(array &$arr, $names)
Causes the elements with the specified names to be output as subelements rather than attributes.
getContext()
Get the base IContextSource object.
An IContextSource implementation which will inherit context from another source but allow individual ...
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
static closeElement( $element)
Returns "</$element>".
static generateTOC( $tree, Language $lang=null)
Generate a table of contents from a section tree.
A class containing constants representing the names of configuration variables.
The Message class deals with fetching and processing of interface message into a variety of formats.
static listParam(array $list, $type='text')
parse()
Fully parse the text from wikitext to HTML.
This is one of the Core classes and should be read at least once by any new developers.
Factory class to create Skin objects.
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,...
static getVersion( $flags='', $lang=null)
Return a string of the MediaWiki version with Git revision if available.
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Interface for objects which can provide a MediaWiki context on request.
getConfig()
Get the site configuration.
msg( $key,... $params)
This is the method for getting translated interface messages.