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