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