MediaWiki REL1_40
ApiQuery.php
Go to the documentation of this file.
1<?php
26use Wikimedia\ObjectFactory\ObjectFactory;
30
42class ApiQuery extends ApiBase {
43
47 private const QUERY_PROP_MODULES = [
48 'categories' => [
49 'class' => ApiQueryCategories::class,
50 ],
51 'categoryinfo' => [
52 'class' => ApiQueryCategoryInfo::class,
53 ],
54 'contributors' => [
55 'class' => ApiQueryContributors::class,
56 'services' => [
57 'RevisionStore',
58 'ActorMigration',
59 'UserGroupManager',
60 'GroupPermissionsLookup',
61 ]
62 ],
63 'deletedrevisions' => [
64 'class' => ApiQueryDeletedRevisions::class,
65 'services' => [
66 'RevisionStore',
67 'ContentHandlerFactory',
68 'ParserFactory',
69 'SlotRoleRegistry',
70 'ChangeTagDefStore',
71 'LinkBatchFactory',
72 'ContentRenderer',
73 'ContentTransformer',
74 'CommentFormatter',
75 ]
76 ],
77 'duplicatefiles' => [
78 'class' => ApiQueryDuplicateFiles::class,
79 'services' => [
80 'RepoGroup',
81 ]
82 ],
83 'extlinks' => [
84 'class' => ApiQueryExternalLinks::class,
85 ],
86 'fileusage' => [
87 'class' => ApiQueryBacklinksprop::class,
88 'services' => [
89 // Same as for linkshere, redirects, transcludedin
90 'LinksMigration',
91 ]
92 ],
93 'images' => [
94 'class' => ApiQueryImages::class,
95 ],
96 'imageinfo' => [
97 'class' => ApiQueryImageInfo::class,
98 'services' => [
99 // Same as for stashimageinfo
100 'RepoGroup',
101 'ContentLanguage',
102 'BadFileLookup',
103 ]
104 ],
105 'info' => [
106 'class' => ApiQueryInfo::class,
107 'services' => [
108 'ContentLanguage',
109 'LinkBatchFactory',
110 'NamespaceInfo',
111 'TitleFactory',
112 'TitleFormatter',
113 'WatchedItemStore',
114 'LanguageConverterFactory',
115 'RestrictionStore',
116 'LinksMigration',
117 ],
118 ],
119 'links' => [
120 'class' => ApiQueryLinks::class,
121 'services' => [
122 // Same as for templates
123 'LinkBatchFactory',
124 'LinksMigration',
125 ]
126 ],
127 'linkshere' => [
128 'class' => ApiQueryBacklinksprop::class,
129 'services' => [
130 // Same as for fileusage, redirects, transcludedin
131 'LinksMigration',
132 ]
133 ],
134 'iwlinks' => [
135 'class' => ApiQueryIWLinks::class,
136 ],
137 'langlinks' => [
138 'class' => ApiQueryLangLinks::class,
139 'services' => [
140 'LanguageNameUtils',
141 'ContentLanguage',
142 ]
143 ],
144 'pageprops' => [
145 'class' => ApiQueryPageProps::class,
146 'services' => [
147 'PageProps',
148 ]
149 ],
150 'redirects' => [
151 'class' => ApiQueryBacklinksprop::class,
152 'services' => [
153 // Same as for fileusage, linkshere, transcludedin
154 'LinksMigration',
155 ]
156 ],
157 'revisions' => [
158 'class' => ApiQueryRevisions::class,
159 'services' => [
160 'RevisionStore',
161 'ContentHandlerFactory',
162 'ParserFactory',
163 'SlotRoleRegistry',
164 'ChangeTagDefStore',
165 'ActorMigration',
166 'ContentRenderer',
167 'ContentTransformer',
168 'CommentFormatter',
169 ]
170 ],
171 'stashimageinfo' => [
172 'class' => ApiQueryStashImageInfo::class,
173 'services' => [
174 // Same as for imageinfo
175 'RepoGroup',
176 'ContentLanguage',
177 'BadFileLookup',
178 ]
179 ],
180 'templates' => [
181 'class' => ApiQueryLinks::class,
182 'services' => [
183 // Same as for links
184 'LinkBatchFactory',
185 'LinksMigration',
186 ]
187 ],
188 'transcludedin' => [
189 'class' => ApiQueryBacklinksprop::class,
190 'services' => [
191 // Same as for fileusage, linkshere, redirects
192 'LinksMigration',
193 ]
194 ],
195 ];
196
200 private const QUERY_LIST_MODULES = [
201 'allcategories' => [
202 'class' => ApiQueryAllCategories::class,
203 ],
204 'alldeletedrevisions' => [
205 'class' => ApiQueryAllDeletedRevisions::class,
206 'services' => [
207 'RevisionStore',
208 'ContentHandlerFactory',
209 'ParserFactory',
210 'SlotRoleRegistry',
211 'ChangeTagDefStore',
212 'NamespaceInfo',
213 'ContentRenderer',
214 'ContentTransformer',
215 'CommentFormatter',
216 ]
217 ],
218 'allfileusages' => [
219 'class' => ApiQueryAllLinks::class,
220 'services' => [
221 // Same as for alllinks, allredirects, alltransclusions
222 'NamespaceInfo',
223 'GenderCache',
224 'LinksMigration',
225 ]
226 ],
227 'allimages' => [
228 'class' => ApiQueryAllImages::class,
229 'services' => [
230 'RepoGroup',
231 'GroupPermissionsLookup',
232 ]
233 ],
234 'alllinks' => [
235 'class' => ApiQueryAllLinks::class,
236 'services' => [
237 // Same as for allfileusages, allredirects, alltransclusions
238 'NamespaceInfo',
239 'GenderCache',
240 'LinksMigration',
241 ]
242 ],
243 'allpages' => [
244 'class' => ApiQueryAllPages::class,
245 'services' => [
246 'NamespaceInfo',
247 'GenderCache',
248 'RestrictionStore',
249 ]
250 ],
251 'allredirects' => [
252 'class' => ApiQueryAllLinks::class,
253 'services' => [
254 // Same as for allfileusages, alllinks, alltransclusions
255 'NamespaceInfo',
256 'GenderCache',
257 'LinksMigration',
258 ]
259 ],
260 'allrevisions' => [
261 'class' => ApiQueryAllRevisions::class,
262 'services' => [
263 'RevisionStore',
264 'ContentHandlerFactory',
265 'ParserFactory',
266 'SlotRoleRegistry',
267 'ActorMigration',
268 'NamespaceInfo',
269 'ContentRenderer',
270 'ContentTransformer',
271 'CommentFormatter',
272 ]
273 ],
274 'mystashedfiles' => [
275 'class' => ApiQueryMyStashedFiles::class,
276 ],
277 'alltransclusions' => [
278 'class' => ApiQueryAllLinks::class,
279 'services' => [
280 // Same as for allfileusages, alllinks, allredirects
281 'NamespaceInfo',
282 'GenderCache',
283 'LinksMigration',
284 ]
285 ],
286 'allusers' => [
287 'class' => ApiQueryAllUsers::class,
288 'services' => [
289 'UserFactory',
290 'UserGroupManager',
291 'GroupPermissionsLookup',
292 'ContentLanguage',
293 ]
294 ],
295 'backlinks' => [
296 'class' => ApiQueryBacklinks::class,
297 'services' => [
298 'LinksMigration',
299 ]
300 ],
301 'blocks' => [
302 'class' => ApiQueryBlocks::class,
303 'services' => [
304 'BlockActionInfo',
305 'BlockRestrictionStore',
306 'CommentStore',
307 ],
308 ],
309 'categorymembers' => [
310 'class' => ApiQueryCategoryMembers::class,
311 'services' => [
312 'CollationFactory',
313 ]
314 ],
315 'deletedrevs' => [
316 'class' => ApiQueryDeletedrevs::class,
317 'services' => [
318 'CommentStore',
319 'RowCommentFormatter',
320 'RevisionStore',
321 'ChangeTagDefStore',
322 'LinkBatchFactory',
323 ],
324 ],
325 'embeddedin' => [
326 'class' => ApiQueryBacklinks::class,
327 'services' => [
328 'LinksMigration',
329 ]
330 ],
331 'exturlusage' => [
332 'class' => ApiQueryExtLinksUsage::class,
333 ],
334 'filearchive' => [
335 'class' => ApiQueryFilearchive::class,
336 'services' => [
337 'CommentStore',
338 'CommentFormatter',
339 ],
340 ],
341 'imageusage' => [
342 'class' => ApiQueryBacklinks::class,
343 'services' => [
344 'LinksMigration',
345 ]
346 ],
347 'iwbacklinks' => [
348 'class' => ApiQueryIWBacklinks::class,
349 ],
350 'langbacklinks' => [
351 'class' => ApiQueryLangBacklinks::class,
352 ],
353 'logevents' => [
354 'class' => ApiQueryLogEvents::class,
355 'services' => [
356 'CommentStore',
357 'RowCommentFormatter',
358 'ChangeTagDefStore',
359 ],
360 ],
361 'pageswithprop' => [
362 'class' => ApiQueryPagesWithProp::class,
363 ],
364 'pagepropnames' => [
365 'class' => ApiQueryPagePropNames::class,
366 ],
367 'prefixsearch' => [
368 'class' => ApiQueryPrefixSearch::class,
369 'services' => [
370 'SearchEngineConfig',
371 'SearchEngineFactory',
372 ],
373 ],
374 'protectedtitles' => [
375 'class' => ApiQueryProtectedTitles::class,
376 'services' => [
377 'CommentStore',
378 'RowCommentFormatter'
379 ],
380 ],
381 'querypage' => [
382 'class' => ApiQueryQueryPage::class,
383 'services' => [
384 'SpecialPageFactory',
385 ]
386 ],
387 'random' => [
388 'class' => ApiQueryRandom::class,
389 ],
390 'recentchanges' => [
391 'class' => ApiQueryRecentChanges::class,
392 'services' => [
393 'CommentStore',
394 'RowCommentFormatter',
395 'ChangeTagDefStore',
396 'SlotRoleStore',
397 'SlotRoleRegistry',
398 ],
399 ],
400 'search' => [
401 'class' => ApiQuerySearch::class,
402 'services' => [
403 'SearchEngineConfig',
404 'SearchEngineFactory',
405 'TitleMatcher',
406 ],
407 ],
408 'tags' => [
409 'class' => ApiQueryTags::class,
410 ],
411 'usercontribs' => [
412 'class' => ApiQueryUserContribs::class,
413 'services' => [
414 'CommentStore',
415 'UserIdentityLookup',
416 'UserNameUtils',
417 'RevisionStore',
418 'ChangeTagDefStore',
419 'ActorMigration',
420 'CommentFormatter',
421 ],
422 ],
423 'users' => [
424 'class' => ApiQueryUsers::class,
425 'services' => [
426 'UserNameUtils',
427 'UserFactory',
428 'UserGroupManager',
429 'GenderCache',
430 'AuthManager',
431 ],
432 ],
433 'watchlist' => [
434 'class' => ApiQueryWatchlist::class,
435 'services' => [
436 'CommentStore',
437 'WatchedItemQueryService',
438 'ContentLanguage',
439 'NamespaceInfo',
440 'GenderCache',
441 'CommentFormatter',
442 ],
443 ],
444 'watchlistraw' => [
445 'class' => ApiQueryWatchlistRaw::class,
446 'services' => [
447 'WatchedItemQueryService',
448 'ContentLanguage',
449 'NamespaceInfo',
450 'GenderCache',
451 ]
452 ],
453 ];
454
458 private const QUERY_META_MODULES = [
459 'allmessages' => [
460 'class' => ApiQueryAllMessages::class,
461 'services' => [
462 'ContentLanguage',
463 'LanguageFactory',
464 'LanguageNameUtils',
465 'LocalisationCache',
466 'MessageCache',
467 ]
468 ],
469 'authmanagerinfo' => [
470 'class' => ApiQueryAuthManagerInfo::class,
471 'services' => [
472 'AuthManager',
473 ]
474 ],
475 'siteinfo' => [
476 'class' => ApiQuerySiteinfo::class,
477 'services' => [
478 'UserOptionsLookup',
479 'UserGroupManager',
480 'LanguageConverterFactory',
481 'LanguageFactory',
482 'LanguageNameUtils',
483 'ContentLanguage',
484 'NamespaceInfo',
485 'InterwikiLookup',
486 'Parser',
487 'MagicWordFactory',
488 'SpecialPageFactory',
489 'SkinFactory',
490 'DBLoadBalancer',
491 'ReadOnlyMode',
492 ]
493 ],
494 'userinfo' => [
495 'class' => ApiQueryUserInfo::class,
496 'services' => [
497 'TalkPageNotificationManager',
498 'WatchedItemStore',
499 'UserEditTracker',
500 'UserOptionsLookup',
501 'UserGroupManager',
502 ]
503 ],
504 'filerepoinfo' => [
505 'class' => ApiQueryFileRepoInfo::class,
506 'services' => [
507 'RepoGroup',
508 ]
509 ],
510 'tokens' => [
511 'class' => ApiQueryTokens::class,
512 ],
513 'languageinfo' => [
514 'class' => ApiQueryLanguageinfo::class,
515 'services' => [
516 'LanguageFactory',
517 'LanguageNameUtils',
518 'LanguageFallback',
519 'LanguageConverterFactory',
520 ],
521 ],
522 ];
523
527 private $mPageSet;
528
529 private $mParams;
530 private $mNamedDB = [];
531 private $mModuleMgr;
532
534 private $loadBalancer;
535
537 private $wikiExporterFactory;
538
546 public function __construct(
547 ApiMain $main,
548 $action,
549 ObjectFactory $objectFactory,
550 ILoadBalancer $loadBalancer,
551 WikiExporterFactory $wikiExporterFactory
552 ) {
553 parent::__construct( $main, $action );
554
555 $this->mModuleMgr = new ApiModuleManager(
556 $this,
557 $objectFactory
558 );
559
560 // Allow custom modules to be added in LocalSettings.php
561 $config = $this->getConfig();
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' );
568
569 $this->getHookRunner()->onApiQuery__moduleManager( $this->mModuleMgr );
570
571 // Create PageSet that will process titles/pageids/revids/generator
572 $this->mPageSet = new ApiPageSet( $this );
573 $this->loadBalancer = $loadBalancer;
574 $this->wikiExporterFactory = $wikiExporterFactory;
575 }
576
581 public function getModuleManager() {
582 return $this->mModuleMgr;
583 }
584
599 public function getNamedDB( $name, $db, $groups ) {
600 wfDeprecated( __METHOD__, '1.39' );
601 if ( !array_key_exists( $name, $this->mNamedDB ) ) {
602 $this->mNamedDB[$name] = $this->loadBalancer->getConnectionRef( $db, $groups );
603 }
604
605 return $this->mNamedDB[$name];
606 }
607
612 public function getPageSet() {
613 return $this->mPageSet;
614 }
615
619 public function getCustomPrinter() {
620 // If &exportnowrap is set, use the raw formatter
621 if ( $this->getParameter( 'export' ) &&
622 $this->getParameter( 'exportnowrap' )
623 ) {
624 return new ApiFormatRaw( $this->getMain(),
625 $this->getMain()->createPrinterByName( 'xml' ) );
626 } else {
627 return null;
628 }
629 }
630
641 public function execute() {
642 $this->mParams = $this->extractRequestParams();
643
644 // Instantiate requested modules
645 $allModules = [];
646 $this->instantiateModules( $allModules, 'prop' );
647 $propModules = array_keys( $allModules );
648 $this->instantiateModules( $allModules, 'list' );
649 $this->instantiateModules( $allModules, 'meta' );
650
651 // Filter modules based on continue parameter
652 $continuationManager = new ApiContinuationManager( $this, $allModules, $propModules );
653 $this->setContinuationManager( $continuationManager );
655 $modules = $continuationManager->getRunModules();
656 '@phan-var ApiQueryBase[] $modules';
657
658 if ( !$continuationManager->isGeneratorDone() ) {
659 // Query modules may optimize data requests through the $this->getPageSet()
660 // object by adding extra fields from the page table.
661 foreach ( $modules as $module ) {
662 $module->requestExtraData( $this->mPageSet );
663 }
664 // Populate page/revision information
665 $this->mPageSet->execute();
666 // Record page information (title, namespace, if exists, etc)
667 $this->outputGeneralPageInfo();
668 } else {
669 $this->mPageSet->executeDryRun();
670 }
671
672 $cacheMode = $this->mPageSet->getCacheMode();
673
674 // Execute all unfinished modules
675 foreach ( $modules as $module ) {
676 $params = $module->extractRequestParams();
677 $cacheMode = $this->mergeCacheMode(
678 $cacheMode, $module->getCacheMode( $params ) );
679 $module->execute();
680 $this->getHookRunner()->onAPIQueryAfterExecute( $module );
681 }
682
683 // Set the cache mode
684 $this->getMain()->setCacheMode( $cacheMode );
685
686 // Write the continuation data into the result
687 $this->setContinuationManager( null );
688 if ( $this->mParams['rawcontinue'] ) {
689 $data = $continuationManager->getRawNonContinuation();
690 if ( $data ) {
691 $this->getResult()->addValue( null, 'query-noncontinue', $data,
692 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
693 }
694 $data = $continuationManager->getRawContinuation();
695 if ( $data ) {
696 $this->getResult()->addValue( null, 'query-continue', $data,
697 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
698 }
699 } else {
700 $continuationManager->setContinuationIntoResult( $this->getResult() );
701 }
702 }
703
713 protected function mergeCacheMode( $cacheMode, $modCacheMode ) {
714 if ( $modCacheMode === 'anon-public-user-private' ) {
715 if ( $cacheMode !== 'private' ) {
716 $cacheMode = 'anon-public-user-private';
717 }
718 } elseif ( $modCacheMode === 'public' ) {
719 // do nothing, if it's public already it will stay public
720 } else {
721 $cacheMode = 'private';
722 }
723
724 return $cacheMode;
725 }
726
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' );
739 }
740 if ( !$wasPosted && $instance->mustBePosted() ) {
741 $this->dieWithErrorOrDebug( [ 'apierror-mustbeposted', $moduleName ] );
742 }
743 // Ignore duplicates. TODO 2.0: die()?
744 if ( !array_key_exists( $moduleName, $modules ) ) {
745 $modules[$moduleName] = $instance;
746 }
747 }
748 }
749 }
750
756 private function outputGeneralPageInfo() {
757 $pageSet = $this->getPageSet();
758 $result = $this->getResult();
759
760 // We can't really handle max-result-size failure here, but we need to
761 // check anyway in case someone set the limit stupidly low.
762 $fit = true;
763
764 $values = $pageSet->getNormalizedTitlesAsResult( $result );
765 if ( $values ) {
766 // @phan-suppress-next-line PhanRedundantCondition
767 $fit = $fit && $result->addValue( 'query', 'normalized', $values );
768 }
769 $values = $pageSet->getConvertedTitlesAsResult( $result );
770 if ( $values ) {
771 $fit = $fit && $result->addValue( 'query', 'converted', $values );
772 }
773 $values = $pageSet->getInterwikiTitlesAsResult( $result, $this->mParams['iwurl'] );
774 if ( $values ) {
775 $fit = $fit && $result->addValue( 'query', 'interwiki', $values );
776 }
777 $values = $pageSet->getRedirectTitlesAsResult( $result );
778 if ( $values ) {
779 $fit = $fit && $result->addValue( 'query', 'redirects', $values );
780 }
781 $values = $pageSet->getMissingRevisionIDsAsResult( $result );
782 if ( $values ) {
783 $fit = $fit && $result->addValue( 'query', 'badrevids', $values );
784 }
785
786 // Page elements
787 $pages = [];
788
789 // Report any missing titles
790 foreach ( $pageSet->getMissingTitles() as $fakeId => $title ) {
791 $vals = [];
793 $vals['missing'] = true;
794 if ( $title->isKnown() ) {
795 $vals['known'] = true;
796 }
797 $pages[$fakeId] = $vals;
798 }
799 // Report any invalid titles
800 foreach ( $pageSet->getInvalidTitlesAndReasons() as $fakeId => $data ) {
801 $pages[$fakeId] = $data + [ 'invalid' => true ];
802 }
803 // Report any missing page ids
804 foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
805 $pages[$pageid] = [
806 'pageid' => $pageid,
807 'missing' => true,
808 ];
809 }
810 // Report special pages
812 foreach ( $pageSet->getSpecialTitles() as $fakeId => $title ) {
813 $vals = [];
815 $vals['special'] = true;
816 if ( !$title->isKnown() ) {
817 $vals['missing'] = true;
818 }
819 $pages[$fakeId] = $vals;
820 }
821
822 // Output general page information for found titles
823 foreach ( $pageSet->getGoodTitles() as $pageid => $title ) {
824 $vals = [];
825 $vals['pageid'] = $pageid;
827 $pages[$pageid] = $vals;
828 }
829
830 if ( count( $pages ) ) {
831 $pageSet->populateGeneratorData( $pages );
832 ApiResult::setArrayType( $pages, 'BCarray' );
833
834 if ( $this->mParams['indexpageids'] ) {
835 $pageIDs = array_keys( ApiResult::stripMetadataNonRecursive( $pages ) );
836 // json treats all map keys as strings - converting to match
837 $pageIDs = array_map( 'strval', $pageIDs );
838 ApiResult::setIndexedTagName( $pageIDs, 'id' );
839 $fit = $fit && $result->addValue( 'query', 'pageids', $pageIDs );
840 }
841
842 ApiResult::setIndexedTagName( $pages, 'page' );
843 $fit = $fit && $result->addValue( 'query', 'pages', $pages );
844 }
845
846 if ( !$fit ) {
847 $this->dieWithError( 'apierror-badconfig-resulttoosmall', 'badconfig' );
848 }
849
850 if ( $this->mParams['export'] ) {
851 $this->doExport( $pageSet, $result );
852 }
853 }
854
859 private function doExport( $pageSet, $result ) {
860 $exportTitles = [];
861 $titles = $pageSet->getGoodPages();
862 if ( count( $titles ) ) {
864 foreach ( $titles as $title ) {
865 if ( $this->getAuthority()->authorizeRead( 'read', $title ) ) {
866 $exportTitles[] = $title;
867 }
868 }
869 }
870
871 $exporter = $this->wikiExporterFactory->getWikiExporter( $this->getDB() );
872 $sink = new DumpStringOutput;
873 $exporter->setOutputSink( $sink );
874 $exporter->setSchemaVersion( $this->mParams['exportschema'] );
875 $exporter->openStream();
876 foreach ( $exportTitles as $title ) {
877 $exporter->pageByTitle( $title );
878 }
879 $exporter->closeStream();
880
881 // Don't check the size of exported stuff
882 // It's not continuable, so it would cause more
883 // problems than it'd solve
884 if ( $this->mParams['exportnowrap'] ) {
885 $result->reset();
886 // Raw formatter will handle this
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 );
890 } else {
891 $result->addValue( 'query', 'export', $sink, ApiResult::NO_SIZE_CHECK );
892 $result->addValue( 'query', ApiResult::META_BC_SUBELEMENTS, [ 'export' ] );
893 }
894 }
895
896 public function getAllowedParams( $flags = 0 ) {
897 $result = [
898 'prop' => [
899 ParamValidator::PARAM_ISMULTI => true,
900 ParamValidator::PARAM_TYPE => 'submodule',
901 ],
902 'list' => [
903 ParamValidator::PARAM_ISMULTI => true,
904 ParamValidator::PARAM_TYPE => 'submodule',
905 ],
906 'meta' => [
907 ParamValidator::PARAM_ISMULTI => true,
908 ParamValidator::PARAM_TYPE => 'submodule',
909 ],
910 'indexpageids' => false,
911 'export' => false,
912 'exportnowrap' => false,
913 'exportschema' => [
914 ParamValidator::PARAM_DEFAULT => WikiExporter::schemaVersion(),
915 ParamValidator::PARAM_TYPE => XmlDumpWriter::$supportedSchemas,
916 ],
917 'iwurl' => false,
918 'continue' => [
919 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
920 ],
921 'rawcontinue' => false,
922 ];
923 if ( $flags ) {
924 $result += $this->getPageSet()->getFinalParams( $flags );
925 }
926
927 return $result;
928 }
929
930 public function isReadMode() {
931 // We need to make an exception for certain meta modules that should be
932 // accessible even without the 'read' right. Restrict the exception as
933 // much as possible: no other modules allowed, and no pageset
934 // parameters either. We do allow the 'rawcontinue' and 'indexpageids'
935 // parameters since frameworks might add these unconditionally and they
936 // can't expose anything here.
937 $allowedParams = [ 'rawcontinue' => 1, 'indexpageids' => 1 ];
938 $this->mParams = $this->extractRequestParams();
939 $request = $this->getRequest();
940 foreach ( $this->mParams + $this->getPageSet()->extractRequestParams() as $param => $value ) {
941 $needed = $param === 'meta';
942 if ( !isset( $allowedParams[$param] ) && $request->getCheck( $param ) !== $needed ) {
943 return true;
944 }
945 }
946
947 // Ask each module if it requires read mode. Any true => this returns
948 // true.
949 $modules = [];
950 $this->instantiateModules( $modules, 'meta' );
951 foreach ( $modules as $module ) {
952 if ( $module->isReadMode() ) {
953 return true;
954 }
955 }
956
957 return false;
958 }
959
960 protected function getExamplesMessages() {
961 $title = Title::newMainPage()->getPrefixedText();
962 $mp = rawurlencode( $title );
963
964 return [
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',
970 ];
971 }
972
973 public function getHelpUrls() {
974 return [
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',
979 ];
980 }
981}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:59
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1460
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition ApiBase.php:894
getDB()
Gets a default replica DB connection object.
Definition ApiBase.php:660
dieWithErrorOrDebug( $msg, $code=null, $data=null, $httpCode=null)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
Definition ApiBase.php:1631
getMain()
Get the main module.
Definition ApiBase.php:522
setContinuationManager(ApiContinuationManager $manager=null)
Definition ApiBase.php:681
getResult()
Get the result object.
Definition ApiBase.php:637
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:773
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:166
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition ApiBase.php:719
This manages continuation state.
Formatter that spits out anything you like with any desired MIME type.
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:58
This class holds a list of modules and handles instantiation.
This class contains a list of pages that the client has requested.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
This is the main query class.
Definition ApiQuery.php:42
isReadMode()
Indicates whether this module requires read rights.
Definition ApiQuery.php:930
mergeCacheMode( $cacheMode, $modCacheMode)
Update a cache mode string, applying the cache mode of a new module to it.
Definition ApiQuery.php:713
getAllowedParams( $flags=0)
Definition ApiQuery.php:896
getModuleManager()
Overrides to return this instance's module manager.
Definition ApiQuery.php:581
getExamplesMessages()
Returns usage examples for this module.
Definition ApiQuery.php:960
__construct(ApiMain $main, $action, ObjectFactory $objectFactory, ILoadBalancer $loadBalancer, WikiExporterFactory $wikiExporterFactory)
Definition ApiQuery.php:546
getHelpUrls()
Return links to more detailed help pages about the module.
Definition ApiQuery.php:973
getPageSet()
Gets the set of pages the user has requested (or generated)
Definition ApiQuery.php:612
execute()
Query execution happens in the following steps: #1 Create a PageSet object with any pages requested b...
Definition ApiQuery.php:641
getNamedDB( $name, $db, $groups)
Get a cached database connection with a given name.
Definition ApiQuery.php:599
getCustomPrinter()
Definition ApiQuery.php:619
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Factory service for WikiExporter instances.
A class containing constants representing the names of configuration variables.
Represents a title within MediaWiki.
Definition Title.php:82
Service for formatting and validating API parameters.
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:36
This class is a delegate to ILBFactory for a given database cluster.
return true
Definition router.php:92