29 use Wikimedia\ObjectFactory\ObjectFactory;
48 private const QUERY_PROP_MODULES = [
50 'class' => ApiQueryCategories::class,
53 'class' => ApiQueryCategoryInfo::class,
56 'class' => ApiQueryContributors::class,
61 'GroupPermissionsLookup',
64 'deletedrevisions' => [
65 'class' => ApiQueryDeletedRevisions::class,
68 'ContentHandlerFactory',
81 'class' => ApiQueryDuplicateFiles::class,
87 'class' => ApiQueryExternalLinks::class,
93 'class' => ApiQueryBacklinksprop::class,
100 'class' => ApiQueryImages::class,
103 'class' => ApiQueryImageInfo::class,
112 'class' => ApiQueryInfo::class,
120 'LanguageConverterFactory',
124 'IntroMessageBuilder',
125 'PreloadedContentBuilder',
131 'class' => ApiQueryLinks::class,
139 'class' => ApiQueryBacklinksprop::class,
146 'class' => ApiQueryIWLinks::class,
152 'class' => ApiQueryLangLinks::class,
160 'class' => ApiQueryPageProps::class,
166 'class' => ApiQueryBacklinksprop::class,
173 'class' => ApiQueryRevisions::class,
176 'ContentHandlerFactory',
182 'ContentTransformer',
188 'stashimageinfo' => [
189 'class' => ApiQueryStashImageInfo::class,
198 'class' => ApiQueryLinks::class,
206 'class' => ApiQueryBacklinksprop::class,
217 private const QUERY_LIST_MODULES = [
219 'class' => ApiQueryAllCategories::class,
221 'alldeletedrevisions' => [
222 'class' => ApiQueryAllDeletedRevisions::class,
225 'ContentHandlerFactory',
231 'ContentTransformer',
238 'class' => ApiQueryAllLinks::class,
247 'class' => ApiQueryAllImages::class,
250 'GroupPermissionsLookup',
254 'class' => ApiQueryAllLinks::class,
263 'class' => ApiQueryAllPages::class,
271 'class' => ApiQueryAllLinks::class,
280 'class' => ApiQueryAllRevisions::class,
283 'ContentHandlerFactory',
289 'ContentTransformer',
295 'mystashedfiles' => [
296 'class' => ApiQueryMyStashedFiles::class,
298 'alltransclusions' => [
299 'class' => ApiQueryAllLinks::class,
308 'class' => ApiQueryAllUsers::class,
312 'GroupPermissionsLookup',
317 'class' => ApiQueryBacklinks::class,
323 'class' => ApiQueryBlocks::class,
326 'BlockRestrictionStore',
330 'categorymembers' => [
331 'class' => ApiQueryCategoryMembers::class,
337 'class' => ApiQueryDeletedrevs::class,
340 'RowCommentFormatter',
347 'class' => ApiQueryBacklinks::class,
353 'class' => ApiQueryExtLinksUsage::class,
359 'class' => ApiQueryFilearchive::class,
366 'class' => ApiQueryBacklinks::class,
372 'class' => ApiQueryIWBacklinks::class,
375 'class' => ApiQueryLangBacklinks::class,
378 'class' => ApiQueryLogEvents::class,
381 'RowCommentFormatter',
386 'class' => ApiQueryPagesWithProp::class,
389 'class' => ApiQueryPagePropNames::class,
392 'class' => ApiQueryPrefixSearch::class,
394 'SearchEngineConfig',
395 'SearchEngineFactory',
398 'protectedtitles' => [
399 'class' => ApiQueryProtectedTitles::class,
402 'RowCommentFormatter'
406 'class' => ApiQueryQueryPage::class,
408 'SpecialPageFactory',
412 'class' => ApiQueryRandom::class,
415 'class' => ApiQueryRecentChanges::class,
418 'RowCommentFormatter',
425 'class' => ApiQuerySearch::class,
427 'SearchEngineConfig',
428 'SearchEngineFactory',
433 'class' => ApiQueryTags::class,
439 'class' => ApiQueryUserContribs::class,
442 'UserIdentityLookup',
451 'class' => ApiQueryUsers::class,
461 'class' => ApiQueryWatchlist::class,
464 'WatchedItemQueryService',
472 'class' => ApiQueryWatchlistRaw::class,
474 'WatchedItemQueryService',
485 private const QUERY_META_MODULES = [
487 'class' => ApiQueryAllMessages::class,
496 'authmanagerinfo' => [
497 'class' => ApiQueryAuthManagerInfo::class,
503 'class' => ApiQuerySiteinfo::class,
507 'LanguageConverterFactory',
515 'SpecialPageFactory',
523 'class' => ApiQueryUserInfo::class,
525 'TalkPageNotificationManager',
533 'class' => ApiQueryFileRepoInfo::class,
539 'class' => ApiQueryTokens::class,
542 'class' => ApiQueryLanguageinfo::class,
547 'LanguageConverterFactory',
575 ObjectFactory $objectFactory,
580 parent::__construct( $main, $action );
589 $this->mModuleMgr->addModules( self::QUERY_PROP_MODULES,
'prop' );
590 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIPropModules ),
'prop' );
591 $this->mModuleMgr->addModules( self::QUERY_LIST_MODULES,
'list' );
592 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIListModules ),
'list' );
593 $this->mModuleMgr->addModules( self::QUERY_META_MODULES,
'meta' );
594 $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIMetaModules ),
'meta' );
596 $this->
getHookRunner()->onApiQuery__moduleManager( $this->mModuleMgr );
600 $this->wikiExporterFactory = $wikiExporterFactory;
601 $this->titleFormatter = $titleFormatter;
602 $this->titleFactory = $titleFactory;
610 return $this->mModuleMgr;
618 return $this->mPageSet;
630 $this->
getMain()->createPrinterByName(
'xml' ) );
651 $this->instantiateModules( $allModules,
'prop' );
652 $propModules = array_keys( $allModules );
653 $this->instantiateModules( $allModules,
'list' );
654 $this->instantiateModules( $allModules,
'meta' );
660 $modules = $continuationManager->getRunModules();
661 '@phan-var ApiQueryBase[] $modules';
663 $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
665 if ( !$continuationManager->isGeneratorDone() ) {
669 $t = microtime(
true );
670 $module->requestExtraData( $this->mPageSet );
671 $runTime = microtime(
true ) -
$t;
675 'api-query.' . $module->getModuleName() .
'.extraDataTiming', 1000 * $runTime
679 $this->mPageSet->execute();
681 $this->outputGeneralPageInfo();
683 $this->mPageSet->executeDryRun();
686 $cacheMode = $this->mPageSet->getCacheMode();
690 $params = $module->extractRequestParams();
692 $cacheMode, $module->getCacheMode( $params ) );
694 $t = microtime(
true );
696 $runTime = microtime(
true ) -
$t;
700 'api-query.' . $module->getModuleName() .
'.executeTiming', 1000 * $runTime
707 $this->
getMain()->setCacheMode( $cacheMode );
711 if ( $this->mParams[
'rawcontinue'] ) {
712 $data = $continuationManager->getRawNonContinuation();
714 $this->
getResult()->addValue(
null,
'query-noncontinue', $data,
717 $data = $continuationManager->getRawContinuation();
719 $this->
getResult()->addValue(
null,
'query-continue', $data,
723 $continuationManager->setContinuationIntoResult( $this->
getResult() );
737 if ( $modCacheMode ===
'anon-public-user-private' ) {
738 if ( $cacheMode !==
'private' ) {
739 $cacheMode =
'anon-public-user-private';
741 } elseif ( $modCacheMode ===
'public' ) {
744 $cacheMode =
'private';
755 private function instantiateModules( &
$modules, $param ) {
756 $wasPosted = $this->
getRequest()->wasPosted();
757 if ( isset( $this->mParams[$param] ) ) {
758 foreach ( $this->mParams[$param] as $moduleName ) {
759 $instance = $this->mModuleMgr->getModule( $moduleName, $param );
760 if ( $instance ===
null ) {
763 if ( !$wasPosted && $instance->mustBePosted() ) {
767 if ( !array_key_exists( $moduleName,
$modules ) ) {
779 private function outputGeneralPageInfo() {
787 $values = $pageSet->getNormalizedTitlesAsResult( $result );
790 $fit = $fit && $result->addValue(
'query',
'normalized', $values );
792 $values = $pageSet->getConvertedTitlesAsResult( $result );
794 $fit = $fit && $result->addValue(
'query',
'converted', $values );
796 $values = $pageSet->getInterwikiTitlesAsResult( $result, $this->mParams[
'iwurl'] );
798 $fit = $fit && $result->addValue(
'query',
'interwiki', $values );
800 $values = $pageSet->getRedirectTitlesAsResult( $result );
802 $fit = $fit && $result->addValue(
'query',
'redirects', $values );
804 $values = $pageSet->getMissingRevisionIDsAsResult( $result );
806 $fit = $fit && $result->addValue(
'query',
'badrevids', $values );
814 foreach ( $pageSet->getMissingPages() as $fakeId => $page ) {
816 $vals[
'ns'] = $page->getNamespace();
817 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
818 $vals[
'missing'] =
true;
819 $title = $this->titleFactory->newFromPageIdentity( $page );
820 if ( $title->isKnown() ) {
821 $vals[
'known'] =
true;
823 $pages[$fakeId] = $vals;
826 foreach ( $pageSet->getInvalidTitlesAndReasons() as $fakeId => $data ) {
827 $pages[$fakeId] = $data + [
'invalid' =>
true ];
830 foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
838 foreach ( $pageSet->getSpecialPages() as $fakeId => $page ) {
840 $vals[
'ns'] = $page->getNamespace();
841 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
842 $vals[
'special'] =
true;
843 $title = $this->titleFactory->newFromPageReference( $page );
844 if ( !$title->isKnown() ) {
845 $vals[
'missing'] =
true;
847 $pages[$fakeId] = $vals;
851 foreach ( $pageSet->getGoodPages() as $pageid => $page ) {
853 $vals[
'pageid'] = $pageid;
854 $vals[
'ns'] = $page->getNamespace();
855 $vals[
'title'] = $this->titleFormatter->getPrefixedText( $page );
856 $pages[$pageid] = $vals;
859 if ( count( $pages ) ) {
860 $pageSet->populateGeneratorData( $pages );
863 if ( $this->mParams[
'indexpageids'] ) {
866 $pageIDs = array_map(
'strval', $pageIDs );
868 $fit = $fit && $result->addValue(
'query',
'pageids', $pageIDs );
872 $fit = $fit && $result->addValue(
'query',
'pages', $pages );
876 $this->
dieWithError(
'apierror-badconfig-resulttoosmall',
'badconfig' );
879 if ( $this->mParams[
'export'] ) {
880 $this->doExport( $pageSet, $result );
888 private function doExport( $pageSet, $result ) {
890 $titles = $pageSet->getGoodPages();
891 if ( count( $titles ) ) {
893 foreach ( $titles as $title ) {
894 if ( $this->
getAuthority()->authorizeRead(
'read', $title ) ) {
895 $exportTitles[] = $title;
900 $exporter = $this->wikiExporterFactory->getWikiExporter( $this->
getDB() );
902 $exporter->setOutputSink( $sink );
903 $exporter->setSchemaVersion( $this->mParams[
'exportschema'] );
904 $exporter->openStream();
905 foreach ( $exportTitles as $title ) {
906 $exporter->pageByTitle( $title );
908 $exporter->closeStream();
913 if ( $this->mParams[
'exportnowrap'] ) {
928 ParamValidator::PARAM_ISMULTI =>
true,
929 ParamValidator::PARAM_TYPE =>
'submodule',
932 ParamValidator::PARAM_ISMULTI =>
true,
933 ParamValidator::PARAM_TYPE =>
'submodule',
936 ParamValidator::PARAM_ISMULTI =>
true,
937 ParamValidator::PARAM_TYPE =>
'submodule',
939 'indexpageids' =>
false,
941 'exportnowrap' =>
false,
950 'rawcontinue' =>
false,
953 $result += $this->
getPageSet()->getFinalParams( $flags );
966 $allowedParams = [
'rawcontinue' => 1,
'indexpageids' => 1 ];
970 $needed = $param ===
'meta';
971 if ( !isset( $allowedParams[$param] ) && $request->getCheck( $param ) !== $needed ) {
979 $this->instantiateModules(
$modules,
'meta' );
981 if ( $module->isReadMode() ) {
990 $title = Title::newMainPage()->getPrefixedText();
991 $mp = rawurlencode( $title );
994 'action=query&prop=revisions&meta=siteinfo&' .
995 "titles={$mp}&rvprop=user|comment&continue="
996 =>
'apihelp-query-example-revisions',
997 'action=query&generator=allpages&gapprefix=API/&prop=revisions&continue='
998 =>
'apihelp-query-example-allpages',
1004 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Query',
1005 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Meta',
1006 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Properties',
1007 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Lists',
This abstract class implements many basic API functions, and is the base of all API classes.
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
getDB()
Gets a default replica DB connection object.
dieWithErrorOrDebug( $msg, $code=null, $data=null, $httpCode=null)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
getMain()
Get the main module.
setContinuationManager(ApiContinuationManager $manager=null)
getResult()
Get the result object.
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
getHookRunner()
Get an ApiHookRunner for running core API hooks.
This manages continuation state.
This is the main API class, used for both external and internal processing.
This class holds a list of modules and handles instantiation.
This class contains a list of pages that the client has requested.
This is the main query class.
isReadMode()
Indicates whether this module requires read rights.
mergeCacheMode( $cacheMode, $modCacheMode)
Update a cache mode string, applying the cache mode of a new module to it.
getAllowedParams( $flags=0)
getModuleManager()
Overrides to return this instance's module manager.
__construct(ApiMain $main, $action, ObjectFactory $objectFactory, WikiExporterFactory $wikiExporterFactory, TitleFormatter $titleFormatter, TitleFactory $titleFactory)
getExamplesMessages()
Returns usage examples for this module.
getHelpUrls()
Return links to more detailed help pages about the module.
getPageSet()
Gets the set of pages the user has requested (or generated)
execute()
Query execution happens in the following steps: #1 Create a PageSet object with any pages requested b...
static stripMetadataNonRecursive( $data, &$metadata=null)
Remove metadata keys from a data array or object, non-recursive.
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
const NO_SIZE_CHECK
For addValue() and similar functions, do not check size while adding a value Don't use this unless yo...
const ADD_ON_TOP
For addValue(), setValue() and similar functions, if the value does not exist, add it as the first el...
const META_BC_SUBELEMENTS
Key for the 'BC subelements' metadata item.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
A class containing constants representing the names of configuration variables.
static schemaVersion()
Returns the default export schema version, as defined by the XmlDumpSchemaVersion setting.
static string[] $supportedSchemas
the schema versions supported for output @final