48 private const QUERY_PROP_MODULES = [
50 'class' => ApiQueryCategories::class,
53 'class' => ApiQueryCategoryInfo::class,
56 'class' => ApiQueryContributors::class,
61 'GroupPermissionsLookup',
65 'deletedrevisions' => [
66 'class' => ApiQueryDeletedRevisions::class,
69 'ContentHandlerFactory',
82 'class' => ApiQueryDuplicateFiles::class,
88 'class' => ApiQueryExternalLinks::class,
94 'class' => ApiQueryBacklinksprop::class,
101 'class' => ApiQueryImages::class,
104 'class' => ApiQueryImageInfo::class,
113 'class' => ApiQueryInfo::class,
121 'LanguageConverterFactory',
126 'IntroMessageBuilder',
127 'PreloadedContentBuilder',
133 'class' => ApiQueryLinks::class,
141 'class' => ApiQueryBacklinksprop::class,
148 'class' => ApiQueryIWLinks::class,
154 'class' => ApiQueryLangLinks::class,
162 'class' => ApiQueryPageProps::class,
168 'class' => ApiQueryBacklinksprop::class,
175 'class' => ApiQueryRevisions::class,
178 'ContentHandlerFactory',
184 'ContentTransformer',
191 'stashimageinfo' => [
192 'class' => ApiQueryStashImageInfo::class,
201 'class' => ApiQueryLinks::class,
209 'class' => ApiQueryBacklinksprop::class,
220 private const QUERY_LIST_MODULES = [
222 'class' => ApiQueryAllCategories::class,
224 'alldeletedrevisions' => [
225 'class' => ApiQueryAllDeletedRevisions::class,
228 'ContentHandlerFactory',
234 'ContentTransformer',
241 'class' => ApiQueryAllLinks::class,
250 'class' => ApiQueryAllImages::class,
253 'GroupPermissionsLookup',
257 'class' => ApiQueryAllLinks::class,
266 'class' => ApiQueryAllPages::class,
274 'class' => ApiQueryAllLinks::class,
283 'class' => ApiQueryAllRevisions::class,
286 'ContentHandlerFactory',
292 'ContentTransformer',
298 'mystashedfiles' => [
299 'class' => ApiQueryMyStashedFiles::class,
301 'alltransclusions' => [
302 'class' => ApiQueryAllLinks::class,
311 'class' => ApiQueryAllUsers::class,
315 'GroupPermissionsLookup',
320 'class' => ApiQueryBacklinks::class,
326 'class' => ApiQueryBlocks::class,
328 'DatabaseBlockStore',
330 'BlockRestrictionStore',
335 'categorymembers' => [
336 'class' => ApiQueryCategoryMembers::class,
342 'class' => ApiQueryDeletedrevs::class,
345 'RowCommentFormatter',
352 'class' => ApiQueryBacklinks::class,
358 'class' => ApiQueryExtLinksUsage::class,
364 'class' => ApiQueryFilearchive::class,
371 'class' => ApiQueryBacklinks::class,
377 'class' => ApiQueryIWBacklinks::class,
380 'class' => ApiQueryLangBacklinks::class,
383 'class' => ApiQueryLogEvents::class,
386 'RowCommentFormatter',
392 'class' => ApiQueryPagesWithProp::class,
395 'class' => ApiQueryPagePropNames::class,
398 'class' => ApiQueryPrefixSearch::class,
400 'SearchEngineConfig',
401 'SearchEngineFactory',
404 'protectedtitles' => [
405 'class' => ApiQueryProtectedTitles::class,
408 'RowCommentFormatter'
412 'class' => ApiQueryQueryPage::class,
414 'SpecialPageFactory',
418 'class' => ApiQueryRandom::class,
421 'class' => ApiQueryRecentChanges::class,
424 'RowCommentFormatter',
432 'class' => ApiQuerySearch::class,
434 'SearchEngineConfig',
435 'SearchEngineFactory',
440 'class' => ApiQueryTags::class,
446 'class' => ApiQueryUserContribs::class,
449 'UserIdentityLookup',
458 'class' => ApiQueryUsers::class,
468 'class' => ApiQueryWatchlist::class,
471 'WatchedItemQueryService',
480 'class' => ApiQueryWatchlistRaw::class,
482 'WatchedItemQueryService',
493 private const QUERY_META_MODULES = [
495 'class' => ApiQueryAllMessages::class,
504 'authmanagerinfo' => [
505 'class' => ApiQueryAuthManagerInfo::class,
511 'class' => ApiQuerySiteinfo::class,
515 'LanguageConverterFactory',
523 'SpecialPageFactory',
532 'class' => ApiQueryUserInfo::class,
534 'TalkPageNotificationManager',
542 'class' => ApiQueryFileRepoInfo::class,
548 'class' => ApiQueryTokens::class,
551 'class' => ApiQueryLanguageinfo::class,
556 'LanguageConverterFactory',
584 ObjectFactory $objectFactory,
589 parent::__construct( $main, $action );
598 $this->mModuleMgr->addModules( self::QUERY_PROP_MODULES,
'prop' );
599 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIPropModules ),
'prop' );
600 $this->mModuleMgr->addModules( self::QUERY_LIST_MODULES,
'list' );
601 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIListModules ),
'list' );
602 $this->mModuleMgr->addModules( self::QUERY_META_MODULES,
'meta' );
603 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIMetaModules ),
'meta' );
605 $this->
getHookRunner()->onApiQuery__moduleManager( $this->mModuleMgr );
609 $this->wikiExporterFactory = $wikiExporterFactory;
610 $this->titleFormatter = $titleFormatter;
611 $this->titleFactory = $titleFactory;
619 return $this->mModuleMgr;
627 return $this->mPageSet;
639 $this->
getMain()->createPrinterByName(
'xml' ) );
660 $this->instantiateModules( $allModules,
'prop' );
661 $propModules = array_keys( $allModules );
662 $this->instantiateModules( $allModules,
'list' );
663 $this->instantiateModules( $allModules,
'meta' );
669 $modules = $continuationManager->getRunModules();
670 '@phan-var ApiQueryBase[] $modules';
672 $statsFactory = MediaWikiServices::getInstance()->getStatsFactory();
674 if ( !$continuationManager->isGeneratorDone() ) {
677 foreach ( $modules as $module ) {
679 $timer = $statsFactory->getTiming(
'api_query_extraDataTiming_seconds' )
680 ->setLabel(
'module', $module->getModuleName() )
681 ->copyToStatsdAt(
'api-query.' . $module->getModuleName() .
'.extraDataTiming' );
683 $module->requestExtraData( $this->mPageSet );
687 $this->mPageSet->execute();
689 $this->outputGeneralPageInfo();
691 $this->mPageSet->executeDryRun();
694 $cacheMode = $this->mPageSet->getCacheMode();
697 foreach ( $modules as $module ) {
699 $timer = $statsFactory->getTiming(
'api_query_executeTiming_seconds' )
700 ->setLabel(
'module', $module->getModuleName() )
701 ->copyToStatsdAt(
'api-query.' . $module->getModuleName() .
'.executeTiming' );
704 $params = $module->extractRequestParams();
706 $cacheMode, $module->getCacheMode(
$params ) );
715 $this->
getMain()->setCacheMode( $cacheMode );
719 if ( $this->mParams[
'rawcontinue'] ) {
720 $data = $continuationManager->getRawNonContinuation();
722 $this->
getResult()->addValue(
null,
'query-noncontinue', $data,
723 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
725 $data = $continuationManager->getRawContinuation();
727 $this->
getResult()->addValue(
null,
'query-continue', $data,
728 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
731 $continuationManager->setContinuationIntoResult( $this->
getResult() );
745 if ( $modCacheMode ===
'anon-public-user-private' ) {
746 if ( $cacheMode !==
'private' ) {
747 $cacheMode =
'anon-public-user-private';
749 } elseif ( $modCacheMode ===
'public' ) {
752 $cacheMode =
'private';
763 private function instantiateModules( &$modules, $param ) {
764 $wasPosted = $this->
getRequest()->wasPosted();
765 if ( isset( $this->mParams[$param] ) ) {
766 foreach ( $this->mParams[$param] as $moduleName ) {
767 $instance = $this->mModuleMgr->getModule( $moduleName, $param );
768 if ( $instance ===
null ) {
769 ApiBase::dieDebug( __METHOD__,
'Error instantiating module' );
771 if ( !$wasPosted && $instance->mustBePosted() ) {
775 if ( !array_key_exists( $moduleName, $modules ) ) {
787 private function outputGeneralPageInfo() {
795 $values = $pageSet->getNormalizedTitlesAsResult( $result );
798 $fit = $fit && $result->addValue(
'query',
'normalized', $values );
800 $values = $pageSet->getConvertedTitlesAsResult( $result );
802 $fit = $fit && $result->addValue(
'query',
'converted', $values );
804 $values = $pageSet->getInterwikiTitlesAsResult( $result, $this->mParams[
'iwurl'] );
806 $fit = $fit && $result->addValue(
'query',
'interwiki', $values );
808 $values = $pageSet->getRedirectTitlesAsResult( $result );
810 $fit = $fit && $result->addValue(
'query',
'redirects', $values );
812 $values = $pageSet->getMissingRevisionIDsAsResult( $result );
814 $fit = $fit && $result->addValue(
'query',
'badrevids', $values );
822 foreach ( $pageSet->getMissingPages() as $fakeId => $page ) {
824 $vals[
'ns'] = $page->getNamespace();
825 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
826 $vals[
'missing'] =
true;
827 $title = $this->titleFactory->newFromPageIdentity( $page );
828 if ( $title->isKnown() ) {
829 $vals[
'known'] =
true;
831 $pages[$fakeId] = $vals;
834 foreach ( $pageSet->getInvalidTitlesAndReasons() as $fakeId => $data ) {
835 $pages[$fakeId] = $data + [
'invalid' => true ];
838 foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
846 foreach ( $pageSet->getSpecialPages() as $fakeId => $page ) {
848 $vals[
'ns'] = $page->getNamespace();
849 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
850 $vals[
'special'] =
true;
851 $title = $this->titleFactory->newFromPageReference( $page );
852 if ( !$title->isKnown() ) {
853 $vals[
'missing'] =
true;
855 $pages[$fakeId] = $vals;
859 foreach ( $pageSet->getGoodPages() as $pageid => $page ) {
861 $vals[
'pageid'] = $pageid;
862 $vals[
'ns'] = $page->getNamespace();
863 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
864 $pages[$pageid] = $vals;
867 if ( count( $pages ) ) {
868 $pageSet->populateGeneratorData( $pages );
871 if ( $this->mParams[
'indexpageids'] ) {
872 $pageIDs = array_keys( ApiResult::stripMetadataNonRecursive( $pages ) );
874 $pageIDs = array_map(
'strval', $pageIDs );
876 $fit = $fit && $result->addValue(
'query',
'pageids', $pageIDs );
880 $fit = $fit && $result->addValue(
'query',
'pages', $pages );
884 $this->
dieWithError(
'apierror-badconfig-resulttoosmall',
'badconfig' );
887 if ( $this->mParams[
'export'] ) {
888 $this->doExport( $pageSet, $result );
896 private function doExport( $pageSet, $result ) {
898 $titles = $pageSet->getGoodPages();
899 if ( count( $titles ) ) {
901 foreach ( $titles as $title ) {
902 if ( $this->
getAuthority()->authorizeRead(
'read', $title ) ) {
903 $exportTitles[] = $title;
908 $exporter = $this->wikiExporterFactory->getWikiExporter( $this->
getDB() );
910 $exporter->setOutputSink( $sink );
911 $exporter->setSchemaVersion( $this->mParams[
'exportschema'] );
912 $exporter->openStream();
913 foreach ( $exportTitles as $title ) {
914 $exporter->pageByTitle( $title );
916 $exporter->closeStream();
921 if ( $this->mParams[
'exportnowrap'] ) {
924 $result->addValue(
null,
'text', $sink, ApiResult::NO_SIZE_CHECK );
925 $result->addValue(
null,
'mime',
'text/xml', ApiResult::NO_SIZE_CHECK );
926 $result->addValue(
null,
'filename',
'export.xml', ApiResult::NO_SIZE_CHECK );
928 $result->addValue(
'query',
'export', $sink, ApiResult::NO_SIZE_CHECK );
929 $result->addValue(
'query', ApiResult::META_BC_SUBELEMENTS, [
'export' ] );
936 ParamValidator::PARAM_ISMULTI =>
true,
937 ParamValidator::PARAM_TYPE =>
'submodule',
940 ParamValidator::PARAM_ISMULTI =>
true,
941 ParamValidator::PARAM_TYPE =>
'submodule',
944 ParamValidator::PARAM_ISMULTI =>
true,
945 ParamValidator::PARAM_TYPE =>
'submodule',
947 'indexpageids' =>
false,
949 'exportnowrap' =>
false,
951 ParamValidator::PARAM_DEFAULT => WikiExporter::schemaVersion(),
952 ParamValidator::PARAM_TYPE => XmlDumpWriter::$supportedSchemas,
958 'rawcontinue' =>
false,
961 $result += $this->
getPageSet()->getFinalParams( $flags );
974 $allowedParams = [
'rawcontinue' => 1,
'indexpageids' => 1 ];
978 $needed = $param ===
'meta';
979 if ( !isset( $allowedParams[$param] ) && $request->getCheck( $param ) !== $needed ) {
987 $this->instantiateModules( $modules,
'meta' );
988 foreach ( $modules as $module ) {
989 if ( $module->isReadMode() ) {
1001 $this->instantiateModules( $modules,
'list' );
1002 $this->instantiateModules( $modules,
'meta' );
1003 $this->instantiateModules( $modules,
'prop' );
1004 foreach ( $modules as $module ) {
1005 if ( $module->isWriteMode() ) {
1014 $title = Title::newMainPage()->getPrefixedText();
1015 $mp = rawurlencode( $title );
1018 'action=query&prop=revisions&meta=siteinfo&' .
1019 "titles={$mp}&rvprop=user|comment&continue="
1020 =>
'apihelp-query-example-revisions',
1021 'action=query&generator=allpages&gapprefix=API/&prop=revisions&continue='
1022 =>
'apihelp-query-example-allpages',
1028 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Query',
1029 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Meta',
1030 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Properties',
1031 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Lists',