47 private const QUERY_PROP_MODULES = [
49 'class' => ApiQueryCategories::class,
52 'class' => ApiQueryCategoryInfo::class,
55 'class' => ApiQueryContributors::class,
60 'GroupPermissionsLookup',
63 'deletedrevisions' => [
64 'class' => ApiQueryDeletedRevisions::class,
67 'ContentHandlerFactory',
78 'class' => ApiQueryDuplicateFiles::class,
84 'class' => ApiQueryExternalLinks::class,
87 'class' => ApiQueryBacklinksprop::class,
94 'class' => ApiQueryImages::class,
97 'class' => ApiQueryImageInfo::class,
106 'class' => ApiQueryInfo::class,
114 'LanguageConverterFactory',
120 'class' => ApiQueryLinks::class,
128 'class' => ApiQueryBacklinksprop::class,
135 'class' => ApiQueryIWLinks::class,
138 'class' => ApiQueryLangLinks::class,
145 'class' => ApiQueryPageProps::class,
151 'class' => ApiQueryBacklinksprop::class,
158 'class' => ApiQueryRevisions::class,
161 'ContentHandlerFactory',
167 'ContentTransformer',
171 'stashimageinfo' => [
172 'class' => ApiQueryStashImageInfo::class,
181 'class' => ApiQueryLinks::class,
189 'class' => ApiQueryBacklinksprop::class,
200 private const QUERY_LIST_MODULES = [
202 'class' => ApiQueryAllCategories::class,
204 'alldeletedrevisions' => [
205 'class' => ApiQueryAllDeletedRevisions::class,
208 'ContentHandlerFactory',
214 'ContentTransformer',
219 'class' => ApiQueryAllLinks::class,
228 'class' => ApiQueryAllImages::class,
231 'GroupPermissionsLookup',
235 'class' => ApiQueryAllLinks::class,
244 'class' => ApiQueryAllPages::class,
252 'class' => ApiQueryAllLinks::class,
261 'class' => ApiQueryAllRevisions::class,
264 'ContentHandlerFactory',
270 'ContentTransformer',
274 'mystashedfiles' => [
275 'class' => ApiQueryMyStashedFiles::class,
277 'alltransclusions' => [
278 'class' => ApiQueryAllLinks::class,
287 'class' => ApiQueryAllUsers::class,
291 'GroupPermissionsLookup',
296 'class' => ApiQueryBacklinks::class,
302 'class' => ApiQueryBlocks::class,
305 'BlockRestrictionStore',
309 'categorymembers' => [
310 'class' => ApiQueryCategoryMembers::class,
316 'class' => ApiQueryDeletedrevs::class,
319 'RowCommentFormatter',
326 'class' => ApiQueryBacklinks::class,
332 'class' => ApiQueryExtLinksUsage::class,
335 'class' => ApiQueryFilearchive::class,
342 'class' => ApiQueryBacklinks::class,
348 'class' => ApiQueryIWBacklinks::class,
351 'class' => ApiQueryLangBacklinks::class,
354 'class' => ApiQueryLogEvents::class,
357 'RowCommentFormatter',
362 'class' => ApiQueryPagesWithProp::class,
365 'class' => ApiQueryPagePropNames::class,
368 'class' => ApiQueryPrefixSearch::class,
370 'SearchEngineConfig',
371 'SearchEngineFactory',
374 'protectedtitles' => [
375 'class' => ApiQueryProtectedTitles::class,
378 'RowCommentFormatter'
382 'class' => ApiQueryQueryPage::class,
384 'SpecialPageFactory',
388 'class' => ApiQueryRandom::class,
391 'class' => ApiQueryRecentChanges::class,
394 'RowCommentFormatter',
401 'class' => ApiQuerySearch::class,
403 'SearchEngineConfig',
404 'SearchEngineFactory',
409 'class' => ApiQueryTags::class,
412 'class' => ApiQueryUserContribs::class,
415 'UserIdentityLookup',
424 'class' => ApiQueryUsers::class,
434 'class' => ApiQueryWatchlist::class,
437 'WatchedItemQueryService',
445 'class' => ApiQueryWatchlistRaw::class,
447 'WatchedItemQueryService',
458 private const QUERY_META_MODULES = [
460 'class' => ApiQueryAllMessages::class,
469 'authmanagerinfo' => [
470 'class' => ApiQueryAuthManagerInfo::class,
476 'class' => ApiQuerySiteinfo::class,
480 'LanguageConverterFactory',
488 'SpecialPageFactory',
495 'class' => ApiQueryUserInfo::class,
497 'TalkPageNotificationManager',
505 'class' => ApiQueryFileRepoInfo::class,
511 'class' => ApiQueryTokens::class,
514 'class' => ApiQueryLanguageinfo::class,
519 'LanguageConverterFactory',
530 private $mNamedDB = [];
534 private $loadBalancer;
537 private $wikiExporterFactory;
549 ObjectFactory $objectFactory,
553 parent::__construct( $main, $action );
562 $this->mModuleMgr->addModules( self::QUERY_PROP_MODULES,
'prop' );
563 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIPropModules ),
'prop' );
564 $this->mModuleMgr->addModules( self::QUERY_LIST_MODULES,
'list' );
565 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIListModules ),
'list' );
566 $this->mModuleMgr->addModules( self::QUERY_META_MODULES,
'meta' );
567 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIMetaModules ),
'meta' );
569 $this->
getHookRunner()->onApiQuery__moduleManager( $this->mModuleMgr );
573 $this->loadBalancer = $loadBalancer;
574 $this->wikiExporterFactory = $wikiExporterFactory;
582 return $this->mModuleMgr;
601 if ( !array_key_exists( $name, $this->mNamedDB ) ) {
602 $this->mNamedDB[$name] = $this->loadBalancer->getConnectionRef( $db, $groups );
605 return $this->mNamedDB[$name];
613 return $this->mPageSet;
625 $this->
getMain()->createPrinterByName(
'xml' ) );
646 $this->instantiateModules( $allModules,
'prop' );
647 $propModules = array_keys( $allModules );
648 $this->instantiateModules( $allModules,
'list' );
649 $this->instantiateModules( $allModules,
'meta' );
655 $modules = $continuationManager->getRunModules();
656 '@phan-var ApiQueryBase[] $modules';
658 if ( !$continuationManager->isGeneratorDone() ) {
662 $module->requestExtraData( $this->mPageSet );
665 $this->mPageSet->execute();
667 $this->outputGeneralPageInfo();
669 $this->mPageSet->executeDryRun();
672 $cacheMode = $this->mPageSet->getCacheMode();
676 $params = $module->extractRequestParams();
678 $cacheMode, $module->getCacheMode( $params ) );
684 $this->
getMain()->setCacheMode( $cacheMode );
688 if ( $this->mParams[
'rawcontinue'] ) {
689 $data = $continuationManager->getRawNonContinuation();
691 $this->
getResult()->addValue(
null,
'query-noncontinue', $data,
692 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
694 $data = $continuationManager->getRawContinuation();
696 $this->
getResult()->addValue(
null,
'query-continue', $data,
697 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
700 $continuationManager->setContinuationIntoResult( $this->
getResult() );
714 if ( $modCacheMode ===
'anon-public-user-private' ) {
715 if ( $cacheMode !==
'private' ) {
716 $cacheMode =
'anon-public-user-private';
718 } elseif ( $modCacheMode ===
'public' ) {
721 $cacheMode =
'private';
732 private function instantiateModules( &
$modules, $param ) {
733 $wasPosted = $this->
getRequest()->wasPosted();
734 if ( isset( $this->mParams[$param] ) ) {
735 foreach ( $this->mParams[$param] as $moduleName ) {
736 $instance = $this->mModuleMgr->getModule( $moduleName, $param );
737 if ( $instance ===
null ) {
738 ApiBase::dieDebug( __METHOD__,
'Error instantiating module' );
740 if ( !$wasPosted && $instance->mustBePosted() ) {
744 if ( !array_key_exists( $moduleName,
$modules ) ) {
756 private function outputGeneralPageInfo() {
764 $values = $pageSet->getNormalizedTitlesAsResult( $result );
767 $fit = $fit && $result->addValue(
'query',
'normalized', $values );
769 $values = $pageSet->getConvertedTitlesAsResult( $result );
771 $fit = $fit && $result->addValue(
'query',
'converted', $values );
773 $values = $pageSet->getInterwikiTitlesAsResult( $result, $this->mParams[
'iwurl'] );
775 $fit = $fit && $result->addValue(
'query',
'interwiki', $values );
777 $values = $pageSet->getRedirectTitlesAsResult( $result );
779 $fit = $fit && $result->addValue(
'query',
'redirects', $values );
781 $values = $pageSet->getMissingRevisionIDsAsResult( $result );
783 $fit = $fit && $result->addValue(
'query',
'badrevids', $values );
790 foreach ( $pageSet->getMissingTitles() as $fakeId =>
$title ) {
793 $vals[
'missing'] =
true;
794 if (
$title->isKnown() ) {
795 $vals[
'known'] =
true;
797 $pages[$fakeId] = $vals;
800 foreach ( $pageSet->getInvalidTitlesAndReasons() as $fakeId => $data ) {
801 $pages[$fakeId] = $data + [
'invalid' =>
true ];
804 foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
812 foreach ( $pageSet->getSpecialTitles() as $fakeId =>
$title ) {
815 $vals[
'special'] =
true;
816 if ( !
$title->isKnown() ) {
817 $vals[
'missing'] =
true;
819 $pages[$fakeId] = $vals;
823 foreach ( $pageSet->getGoodTitles() as $pageid =>
$title ) {
825 $vals[
'pageid'] = $pageid;
827 $pages[$pageid] = $vals;
830 if ( count( $pages ) ) {
831 $pageSet->populateGeneratorData( $pages );
834 if ( $this->mParams[
'indexpageids'] ) {
835 $pageIDs = array_keys( ApiResult::stripMetadataNonRecursive( $pages ) );
837 $pageIDs = array_map(
'strval', $pageIDs );
839 $fit = $fit && $result->addValue(
'query',
'pageids', $pageIDs );
843 $fit = $fit && $result->addValue(
'query',
'pages', $pages );
847 $this->
dieWithError(
'apierror-badconfig-resulttoosmall',
'badconfig' );
850 if ( $this->mParams[
'export'] ) {
851 $this->doExport( $pageSet, $result );
859 private function doExport( $pageSet, $result ) {
861 $titles = $pageSet->getGoodPages();
862 if ( count( $titles ) ) {
864 foreach ( $titles as
$title ) {
871 $exporter = $this->wikiExporterFactory->getWikiExporter( $this->
getDB() );
873 $exporter->setOutputSink( $sink );
874 $exporter->setSchemaVersion( $this->mParams[
'exportschema'] );
875 $exporter->openStream();
876 foreach ( $exportTitles as
$title ) {
877 $exporter->pageByTitle(
$title );
879 $exporter->closeStream();
884 if ( $this->mParams[
'exportnowrap'] ) {
887 $result->addValue(
null,
'text', $sink, ApiResult::NO_SIZE_CHECK );
888 $result->addValue(
null,
'mime',
'text/xml', ApiResult::NO_SIZE_CHECK );
889 $result->addValue(
null,
'filename',
'export.xml', ApiResult::NO_SIZE_CHECK );
891 $result->addValue(
'query',
'export', $sink, ApiResult::NO_SIZE_CHECK );
892 $result->addValue(
'query', ApiResult::META_BC_SUBELEMENTS, [
'export' ] );
899 ParamValidator::PARAM_ISMULTI =>
true,
900 ParamValidator::PARAM_TYPE =>
'submodule',
903 ParamValidator::PARAM_ISMULTI =>
true,
904 ParamValidator::PARAM_TYPE =>
'submodule',
907 ParamValidator::PARAM_ISMULTI =>
true,
908 ParamValidator::PARAM_TYPE =>
'submodule',
910 'indexpageids' =>
false,
912 'exportnowrap' =>
false,
914 ParamValidator::PARAM_DEFAULT => WikiExporter::schemaVersion(),
915 ParamValidator::PARAM_TYPE => XmlDumpWriter::$supportedSchemas,
921 'rawcontinue' =>
false,
924 $result += $this->
getPageSet()->getFinalParams( $flags );
937 $allowedParams = [
'rawcontinue' => 1,
'indexpageids' => 1 ];
941 $needed = $param ===
'meta';
942 if ( !isset( $allowedParams[$param] ) && $request->getCheck( $param ) !== $needed ) {
950 $this->instantiateModules(
$modules,
'meta' );
952 if ( $module->isReadMode() ) {
961 $title = Title::newMainPage()->getPrefixedText();
962 $mp = rawurlencode(
$title );
965 'action=query&prop=revisions&meta=siteinfo&' .
966 "titles={$mp}&rvprop=user|comment&continue="
967 =>
'apihelp-query-example-revisions',
968 'action=query&generator=allpages&gapprefix=API/&prop=revisions&continue='
969 =>
'apihelp-query-example-allpages',
975 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Query',
976 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Meta',
977 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Properties',
978 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Lists',