53 private const QUERY_PROP_MODULES = [
55 'class' => ApiQueryCategories::class,
58 'class' => ApiQueryCategoryInfo::class,
61 'class' => ApiQueryContributors::class,
66 'GroupPermissionsLookup',
70 'deletedrevisions' => [
71 'class' => ApiQueryDeletedRevisions::class,
74 'ContentHandlerFactory',
87 'class' => ApiQueryDuplicateFiles::class,
93 'class' => ApiQueryExternalLinks::class,
99 'class' => ApiQueryBacklinksprop::class,
106 'class' => ApiQueryImages::class,
109 'class' => ApiQueryImageInfo::class,
118 'class' => ApiQueryInfo::class,
126 'LanguageConverterFactory',
131 'IntroMessageBuilder',
132 'PreloadedContentBuilder',
138 'class' => ApiQueryLinks::class,
146 'class' => ApiQueryBacklinksprop::class,
153 'class' => ApiQueryIWLinks::class,
159 'class' => ApiQueryLangLinks::class,
167 'class' => ApiQueryPageProps::class,
173 'class' => ApiQueryBacklinksprop::class,
180 'class' => ApiQueryRevisions::class,
183 'ContentHandlerFactory',
189 'ContentTransformer',
196 'stashimageinfo' => [
197 'class' => ApiQueryStashImageInfo::class,
206 'class' => ApiQueryLinks::class,
214 'class' => ApiQueryBacklinksprop::class,
225 private const QUERY_LIST_MODULES = [
227 'class' => ApiQueryAllCategories::class,
229 'alldeletedrevisions' => [
230 'class' => ApiQueryAllDeletedRevisions::class,
233 'ContentHandlerFactory',
239 'ContentTransformer',
246 'class' => ApiQueryAllLinks::class,
255 'class' => ApiQueryAllImages::class,
258 'GroupPermissionsLookup',
262 'class' => ApiQueryAllLinks::class,
271 'class' => ApiQueryAllPages::class,
279 'class' => ApiQueryAllLinks::class,
288 'class' => ApiQueryAllRevisions::class,
291 'ContentHandlerFactory',
297 'ContentTransformer',
303 'mystashedfiles' => [
304 'class' => ApiQueryMyStashedFiles::class,
306 'alltransclusions' => [
307 'class' => ApiQueryAllLinks::class,
316 'class' => ApiQueryAllUsers::class,
320 'GroupPermissionsLookup',
326 'class' => ApiQueryBacklinks::class,
332 'class' => ApiQueryBlocks::class,
334 'DatabaseBlockStore',
336 'BlockRestrictionStore',
341 'categorymembers' => [
342 'class' => ApiQueryCategoryMembers::class,
348 'class' => ApiQueryDeletedrevs::class,
351 'RowCommentFormatter',
358 'class' => ApiQueryBacklinks::class,
364 'class' => ApiQueryExtLinksUsage::class,
370 'class' => ApiQueryFilearchive::class,
377 'class' => ApiQueryBacklinks::class,
383 'class' => ApiQueryIWBacklinks::class,
386 'class' => ApiQueryLangBacklinks::class,
389 'class' => ApiQueryLogEvents::class,
392 'RowCommentFormatter',
395 'LogFormatterFactory',
399 'class' => ApiQueryPagesWithProp::class,
402 'class' => ApiQueryPagePropNames::class,
405 'class' => ApiQueryPrefixSearch::class,
407 'SearchEngineConfig',
408 'SearchEngineFactory',
411 'protectedtitles' => [
412 'class' => ApiQueryProtectedTitles::class,
415 'RowCommentFormatter'
419 'class' => ApiQueryQueryPage::class,
421 'SpecialPageFactory',
425 'class' => ApiQueryRandom::class,
428 'class' => ApiQueryRecentChanges::class,
431 'RowCommentFormatter',
437 'LogFormatterFactory',
441 'class' => ApiQuerySearch::class,
443 'SearchEngineConfig',
444 'SearchEngineFactory',
449 'class' => ApiQueryTags::class,
455 'class' => ApiQueryUserContribs::class,
458 'UserIdentityLookup',
467 'class' => ApiQueryUsers::class,
477 'class' => ApiQueryWatchlist::class,
480 'WatchedItemQueryService',
486 'LogFormatterFactory',
490 'class' => ApiQueryWatchlistRaw::class,
492 'WatchedItemQueryService',
503 private const QUERY_META_MODULES = [
505 'class' => ApiQueryAllMessages::class,
514 'authmanagerinfo' => [
515 'class' => ApiQueryAuthManagerInfo::class,
521 'class' => ApiQuerySiteinfo::class,
525 'LanguageConverterFactory',
533 'SpecialPageFactory',
542 'class' => ApiQueryUserInfo::class,
544 'TalkPageNotificationManager',
552 'class' => ApiQueryFileRepoInfo::class,
558 'class' => ApiQueryTokens::class,
561 'class' => ApiQueryLanguageinfo::class,
566 'LanguageConverterFactory',
588 ObjectFactory $objectFactory,
593 parent::__construct( $main, $action );
602 $this->mModuleMgr->addModules( self::QUERY_PROP_MODULES,
'prop' );
604 $this->mModuleMgr->addModules( self::QUERY_LIST_MODULES,
'list' );
606 $this->mModuleMgr->addModules( self::QUERY_META_MODULES,
'meta' );
609 $this->
getHookRunner()->onApiQuery__moduleManager( $this->mModuleMgr );
613 $this->wikiExporterFactory = $wikiExporterFactory;
614 $this->titleFormatter = $titleFormatter;
615 $this->titleFactory = $titleFactory;
623 return $this->mModuleMgr;
631 return $this->mPageSet;
643 $this->
getMain()->createPrinterByName(
'xml' ) );
664 $this->instantiateModules( $allModules,
'prop' );
665 $propModules = array_keys( $allModules );
666 $this->instantiateModules( $allModules,
'list' );
667 $this->instantiateModules( $allModules,
'meta' );
673 $modules = $continuationManager->getRunModules();
674 '@phan-var ApiQueryBase[] $modules';
678 if ( !$continuationManager->isGeneratorDone() ) {
681 foreach ( $modules as $module ) {
683 $timer = $statsFactory->getTiming(
'api_query_extraDataTiming_seconds' )
684 ->setLabel(
'module', $module->getModuleName() )
685 ->copyToStatsdAt(
'api-query.' . $module->getModuleName() .
'.extraDataTiming' );
687 $module->requestExtraData( $this->mPageSet );
691 $this->mPageSet->execute();
693 $this->outputGeneralPageInfo();
695 $this->mPageSet->executeDryRun();
698 $cacheMode = $this->mPageSet->getCacheMode();
701 foreach ( $modules as $module ) {
703 $timer = $statsFactory->getTiming(
'api_query_executeTiming_seconds' )
704 ->setLabel(
'module', $module->getModuleName() )
705 ->copyToStatsdAt(
'api-query.' . $module->getModuleName() .
'.executeTiming' );
708 $params = $module->extractRequestParams();
710 $cacheMode, $module->getCacheMode(
$params ) );
719 $this->
getMain()->setCacheMode( $cacheMode );
723 if ( $this->mParams[
'rawcontinue'] ) {
724 $data = $continuationManager->getRawNonContinuation();
726 $this->
getResult()->addValue(
null,
'query-noncontinue', $data,
729 $data = $continuationManager->getRawContinuation();
731 $this->
getResult()->addValue(
null,
'query-continue', $data,
735 $continuationManager->setContinuationIntoResult( $this->
getResult() );
749 if ( $modCacheMode ===
'anon-public-user-private' ) {
750 if ( $cacheMode !==
'private' ) {
751 $cacheMode =
'anon-public-user-private';
753 } elseif ( $modCacheMode ===
'public' ) {
756 $cacheMode =
'private';
767 private function instantiateModules( &$modules, $param ) {
768 $wasPosted = $this->
getRequest()->wasPosted();
769 if ( isset( $this->mParams[$param] ) ) {
770 foreach ( $this->mParams[$param] as $moduleName ) {
771 $instance = $this->mModuleMgr->getModule( $moduleName, $param );
772 if ( $instance ===
null ) {
775 if ( !$wasPosted && $instance->mustBePosted() ) {
779 if ( !array_key_exists( $moduleName, $modules ) ) {
780 $modules[$moduleName] = $instance;
791 private function outputGeneralPageInfo() {
799 $values = $pageSet->getNormalizedTitlesAsResult( $result );
802 $fit = $fit && $result->addValue(
'query',
'normalized', $values );
804 $values = $pageSet->getConvertedTitlesAsResult( $result );
806 $fit = $fit && $result->addValue(
'query',
'converted', $values );
808 $values = $pageSet->getInterwikiTitlesAsResult( $result, $this->mParams[
'iwurl'] );
810 $fit = $fit && $result->addValue(
'query',
'interwiki', $values );
812 $values = $pageSet->getRedirectTitlesAsResult( $result );
814 $fit = $fit && $result->addValue(
'query',
'redirects', $values );
816 $values = $pageSet->getMissingRevisionIDsAsResult( $result );
818 $fit = $fit && $result->addValue(
'query',
'badrevids', $values );
826 foreach ( $pageSet->getMissingPages() as $fakeId => $page ) {
828 $vals[
'ns'] = $page->getNamespace();
829 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
830 $vals[
'missing'] =
true;
831 $title = $this->titleFactory->newFromPageIdentity( $page );
832 if ( $title->isKnown() ) {
833 $vals[
'known'] =
true;
835 $pages[$fakeId] = $vals;
838 foreach ( $pageSet->getInvalidTitlesAndReasons() as $fakeId => $data ) {
839 $pages[$fakeId] = $data + [
'invalid' => true ];
842 foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
850 foreach ( $pageSet->getSpecialPages() as $fakeId => $page ) {
852 $vals[
'ns'] = $page->getNamespace();
853 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
854 $vals[
'special'] =
true;
855 $title = $this->titleFactory->newFromPageReference( $page );
856 if ( !$title->isKnown() ) {
857 $vals[
'missing'] =
true;
859 $pages[$fakeId] = $vals;
863 foreach ( $pageSet->getGoodPages() as $pageid => $page ) {
865 $vals[
'pageid'] = $pageid;
866 $vals[
'ns'] = $page->getNamespace();
867 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
868 $pages[$pageid] = $vals;
871 if ( count( $pages ) ) {
872 $pageSet->populateGeneratorData( $pages );
875 if ( $this->mParams[
'indexpageids'] ) {
878 $pageIDs = array_map(
'strval', $pageIDs );
880 $fit = $fit && $result->addValue(
'query',
'pageids', $pageIDs );
884 $fit = $fit && $result->addValue(
'query',
'pages', $pages );
888 $this->
dieWithError(
'apierror-badconfig-resulttoosmall',
'badconfig' );
891 if ( $this->mParams[
'export'] ) {
892 $this->doExport( $pageSet, $result );
900 private function doExport( $pageSet, $result ) {
902 $titles = $pageSet->getGoodPages();
903 if ( count( $titles ) ) {
905 foreach ( $titles as $title ) {
906 if ( $this->
getAuthority()->authorizeRead(
'read', $title ) ) {
907 $exportTitles[] = $title;
912 $exporter = $this->wikiExporterFactory->getWikiExporter( $this->
getDB() );
914 $exporter->setOutputSink( $sink );
915 $exporter->setSchemaVersion( $this->mParams[
'exportschema'] );
916 $exporter->openStream();
917 foreach ( $exportTitles as $title ) {
918 $exporter->pageByTitle( $title );
920 $exporter->closeStream();
925 if ( $this->mParams[
'exportnowrap'] ) {
940 ParamValidator::PARAM_ISMULTI =>
true,
941 ParamValidator::PARAM_TYPE =>
'submodule',
944 ParamValidator::PARAM_ISMULTI =>
true,
945 ParamValidator::PARAM_TYPE =>
'submodule',
948 ParamValidator::PARAM_ISMULTI =>
true,
949 ParamValidator::PARAM_TYPE =>
'submodule',
951 'indexpageids' =>
false,
953 'exportnowrap' =>
false,
962 'rawcontinue' =>
false,
965 $result += $this->
getPageSet()->getFinalParams( $flags );
978 $allowedParams = [
'rawcontinue' => 1,
'indexpageids' => 1 ];
982 $needed = $param ===
'meta';
983 if ( !isset( $allowedParams[$param] ) && $request->getCheck( $param ) !== $needed ) {
991 $this->instantiateModules( $modules,
'meta' );
992 foreach ( $modules as $module ) {
993 if ( $module->isReadMode() ) {
1005 $this->instantiateModules( $modules,
'list' );
1006 $this->instantiateModules( $modules,
'meta' );
1007 $this->instantiateModules( $modules,
'prop' );
1008 foreach ( $modules as $module ) {
1009 if ( $module->isWriteMode() ) {
1018 $title = Title::newMainPage()->getPrefixedText();
1019 $mp = rawurlencode( $title );
1022 'action=query&prop=revisions&meta=siteinfo&' .
1023 "titles={$mp}&rvprop=user|comment&continue="
1024 =>
'apihelp-query-example-revisions',
1025 'action=query&generator=allpages&gapprefix=API/&prop=revisions&continue='
1026 =>
'apihelp-query-example-allpages',
1032 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Query',
1033 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Meta',
1034 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Properties',
1035 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Lists',
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)