MediaWiki  master
ApiQuery.php
Go to the documentation of this file.
1 <?php
25 use Wikimedia\ObjectFactory\ObjectFactory;
29 
41 class 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  ],
293  'blocks' => [
294  'class' => ApiQueryBlocks::class,
295  'services' => [
296  'BlockActionInfo',
297  'BlockRestrictionStore',
298  'CommentStore',
299  ],
300  ],
301  'categorymembers' => [
302  'class' => ApiQueryCategoryMembers::class,
303  'services' => [
304  'CollationFactory',
305  ]
306  ],
307  'deletedrevs' => [
308  'class' => ApiQueryDeletedrevs::class,
309  'services' => [
310  'CommentStore',
311  'RowCommentFormatter',
312  'RevisionStore',
313  'ChangeTagDefStore',
314  'LinkBatchFactory',
315  ],
316  ],
317  'embeddedin' => [
318  'class' => ApiQueryBacklinks::class,
319  ],
320  'exturlusage' => [
321  'class' => ApiQueryExtLinksUsage::class,
322  ],
323  'filearchive' => [
324  'class' => ApiQueryFilearchive::class,
325  'services' => [
326  'CommentStore',
327  'CommentFormatter',
328  ],
329  ],
330  'imageusage' => [
331  'class' => ApiQueryBacklinks::class,
332  ],
333  'iwbacklinks' => [
334  'class' => ApiQueryIWBacklinks::class,
335  ],
336  'langbacklinks' => [
337  'class' => ApiQueryLangBacklinks::class,
338  ],
339  'logevents' => [
340  'class' => ApiQueryLogEvents::class,
341  'services' => [
342  'CommentStore',
343  'RowCommentFormatter',
344  'ChangeTagDefStore',
345  ],
346  ],
347  'pageswithprop' => [
348  'class' => ApiQueryPagesWithProp::class,
349  ],
350  'pagepropnames' => [
351  'class' => ApiQueryPagePropNames::class,
352  ],
353  'prefixsearch' => [
354  'class' => ApiQueryPrefixSearch::class,
355  'services' => [
356  'SearchEngineConfig',
357  'SearchEngineFactory',
358  ],
359  ],
360  'protectedtitles' => [
361  'class' => ApiQueryProtectedTitles::class,
362  'services' => [
363  'CommentStore',
364  'RowCommentFormatter'
365  ],
366  ],
367  'querypage' => [
368  'class' => ApiQueryQueryPage::class,
369  'services' => [
370  'SpecialPageFactory',
371  ]
372  ],
373  'random' => [
374  'class' => ApiQueryRandom::class,
375  ],
376  'recentchanges' => [
377  'class' => ApiQueryRecentChanges::class,
378  'services' => [
379  'CommentStore',
380  'RowCommentFormatter',
381  'ChangeTagDefStore',
382  'SlotRoleStore',
383  'SlotRoleRegistry',
384  ],
385  ],
386  'search' => [
387  'class' => ApiQuerySearch::class,
388  'services' => [
389  'SearchEngineConfig',
390  'SearchEngineFactory',
391  ],
392  ],
393  'tags' => [
394  'class' => ApiQueryTags::class,
395  ],
396  'usercontribs' => [
397  'class' => ApiQueryUserContribs::class,
398  'services' => [
399  'CommentStore',
400  'UserIdentityLookup',
401  'UserNameUtils',
402  'RevisionStore',
403  'ChangeTagDefStore',
404  'ActorMigration',
405  ],
406  ],
407  'users' => [
408  'class' => ApiQueryUsers::class,
409  'services' => [
410  'UserNameUtils',
411  'UserFactory',
412  'UserGroupManager',
413  'GenderCache',
414  'AuthManager',
415  ],
416  ],
417  'watchlist' => [
418  'class' => ApiQueryWatchlist::class,
419  'services' => [
420  'CommentStore',
421  'WatchedItemQueryService',
422  'ContentLanguage',
423  'NamespaceInfo',
424  'GenderCache',
425  ],
426  ],
427  'watchlistraw' => [
428  'class' => ApiQueryWatchlistRaw::class,
429  'services' => [
430  'WatchedItemQueryService',
431  'ContentLanguage',
432  'NamespaceInfo',
433  'GenderCache',
434  ]
435  ],
436  ];
437 
441  private const QUERY_META_MODULES = [
442  'allmessages' => [
443  'class' => ApiQueryAllMessages::class,
444  'services' => [
445  'ContentLanguage',
446  'LanguageFactory',
447  'LanguageNameUtils',
448  'LocalisationCache',
449  'MessageCache',
450  ]
451  ],
452  'authmanagerinfo' => [
453  'class' => ApiQueryAuthManagerInfo::class,
454  'services' => [
455  'AuthManager',
456  ]
457  ],
458  'siteinfo' => [
459  'class' => ApiQuerySiteinfo::class,
460  'services' => [
461  'UserOptionsLookup',
462  'UserGroupManager',
463  'LanguageConverterFactory',
464  'LanguageFactory',
465  'LanguageNameUtils',
466  'ContentLanguage',
467  'NamespaceInfo',
468  'InterwikiLookup',
469  'Parser',
470  'MagicWordFactory',
471  'SpecialPageFactory',
472  'SkinFactory',
473  'DBLoadBalancer',
474  'ReadOnlyMode',
475  ]
476  ],
477  'userinfo' => [
478  'class' => ApiQueryUserInfo::class,
479  'services' => [
480  'TalkPageNotificationManager',
481  'WatchedItemStore',
482  'UserEditTracker',
483  'UserOptionsLookup',
484  'UserGroupManager',
485  ]
486  ],
487  'filerepoinfo' => [
488  'class' => ApiQueryFileRepoInfo::class,
489  'services' => [
490  'RepoGroup',
491  ]
492  ],
493  'tokens' => [
494  'class' => ApiQueryTokens::class,
495  ],
496  'languageinfo' => [
497  'class' => ApiQueryLanguageinfo::class,
498  'services' => [
499  'LanguageFactory',
500  'LanguageNameUtils',
501  'LanguageFallback',
502  'LanguageConverterFactory',
503  ],
504  ],
505  ];
506 
510  private $mPageSet;
511 
512  private $mParams;
513  private $mNamedDB = [];
514  private $mModuleMgr;
515 
517  private $loadBalancer;
518 
521 
529  public function __construct(
530  ApiMain $main,
531  $action,
532  ObjectFactory $objectFactory,
535  ) {
536  parent::__construct( $main, $action );
537 
538  $this->mModuleMgr = new ApiModuleManager(
539  $this,
540  $objectFactory
541  );
542 
543  // Allow custom modules to be added in LocalSettings.php
544  $config = $this->getConfig();
545  $this->mModuleMgr->addModules( self::QUERY_PROP_MODULES, 'prop' );
546  $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIPropModules ), 'prop' );
547  $this->mModuleMgr->addModules( self::QUERY_LIST_MODULES, 'list' );
548  $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIListModules ), 'list' );
549  $this->mModuleMgr->addModules( self::QUERY_META_MODULES, 'meta' );
550  $this->mModuleMgr->addModules( $config->get( MainConfigNames::APIMetaModules ), 'meta' );
551 
552  $this->getHookRunner()->onApiQuery__moduleManager( $this->mModuleMgr );
553 
554  // Create PageSet that will process titles/pageids/revids/generator
555  $this->mPageSet = new ApiPageSet( $this );
556  $this->loadBalancer = $loadBalancer;
557  $this->wikiExporterFactory = $wikiExporterFactory;
558  }
559 
564  public function getModuleManager() {
565  return $this->mModuleMgr;
566  }
567 
578  public function getNamedDB( $name, $db, $groups ) {
579  if ( !array_key_exists( $name, $this->mNamedDB ) ) {
580  $this->mNamedDB[$name] = $this->loadBalancer->getConnectionRef( $db, $groups );
581  }
582 
583  return $this->mNamedDB[$name];
584  }
585 
590  public function getPageSet() {
591  return $this->mPageSet;
592  }
593 
597  public function getCustomPrinter() {
598  // If &exportnowrap is set, use the raw formatter
599  if ( $this->getParameter( 'export' ) &&
600  $this->getParameter( 'exportnowrap' )
601  ) {
602  return new ApiFormatRaw( $this->getMain(),
603  $this->getMain()->createPrinterByName( 'xml' ) );
604  } else {
605  return null;
606  }
607  }
608 
619  public function execute() {
620  $this->mParams = $this->extractRequestParams();
621 
622  // Instantiate requested modules
623  $allModules = [];
624  $this->instantiateModules( $allModules, 'prop' );
625  $propModules = array_keys( $allModules );
626  $this->instantiateModules( $allModules, 'list' );
627  $this->instantiateModules( $allModules, 'meta' );
628 
629  // Filter modules based on continue parameter
630  $continuationManager = new ApiContinuationManager( $this, $allModules, $propModules );
631  $this->setContinuationManager( $continuationManager );
633  $modules = $continuationManager->getRunModules();
634  '@phan-var ApiQueryBase[] $modules';
635 
636  if ( !$continuationManager->isGeneratorDone() ) {
637  // Query modules may optimize data requests through the $this->getPageSet()
638  // object by adding extra fields from the page table.
639  foreach ( $modules as $module ) {
640  $module->requestExtraData( $this->mPageSet );
641  }
642  // Populate page/revision information
643  $this->mPageSet->execute();
644  // Record page information (title, namespace, if exists, etc)
645  $this->outputGeneralPageInfo();
646  } else {
647  $this->mPageSet->executeDryRun();
648  }
649 
650  $cacheMode = $this->mPageSet->getCacheMode();
651 
652  // Execute all unfinished modules
653  foreach ( $modules as $module ) {
654  $params = $module->extractRequestParams();
655  $cacheMode = $this->mergeCacheMode(
656  $cacheMode, $module->getCacheMode( $params ) );
657  $module->execute();
658  $this->getHookRunner()->onAPIQueryAfterExecute( $module );
659  }
660 
661  // Set the cache mode
662  $this->getMain()->setCacheMode( $cacheMode );
663 
664  // Write the continuation data into the result
665  $this->setContinuationManager( null );
666  if ( $this->mParams['rawcontinue'] ) {
667  $data = $continuationManager->getRawNonContinuation();
668  if ( $data ) {
669  $this->getResult()->addValue( null, 'query-noncontinue', $data,
671  }
672  $data = $continuationManager->getRawContinuation();
673  if ( $data ) {
674  $this->getResult()->addValue( null, 'query-continue', $data,
676  }
677  } else {
678  $continuationManager->setContinuationIntoResult( $this->getResult() );
679  }
680  }
681 
691  protected function mergeCacheMode( $cacheMode, $modCacheMode ) {
692  if ( $modCacheMode === 'anon-public-user-private' ) {
693  if ( $cacheMode !== 'private' ) {
694  $cacheMode = 'anon-public-user-private';
695  }
696  } elseif ( $modCacheMode === 'public' ) {
697  // do nothing, if it's public already it will stay public
698  } else {
699  $cacheMode = 'private';
700  }
701 
702  return $cacheMode;
703  }
704 
710  private function instantiateModules( &$modules, $param ) {
711  $wasPosted = $this->getRequest()->wasPosted();
712  if ( isset( $this->mParams[$param] ) ) {
713  foreach ( $this->mParams[$param] as $moduleName ) {
714  $instance = $this->mModuleMgr->getModule( $moduleName, $param );
715  if ( $instance === null ) {
716  ApiBase::dieDebug( __METHOD__, 'Error instantiating module' );
717  }
718  if ( !$wasPosted && $instance->mustBePosted() ) {
719  $this->dieWithErrorOrDebug( [ 'apierror-mustbeposted', $moduleName ] );
720  }
721  // Ignore duplicates. TODO 2.0: die()?
722  if ( !array_key_exists( $moduleName, $modules ) ) {
723  $modules[$moduleName] = $instance;
724  }
725  }
726  }
727  }
728 
734  private function outputGeneralPageInfo() {
735  $pageSet = $this->getPageSet();
736  $result = $this->getResult();
737 
738  // We can't really handle max-result-size failure here, but we need to
739  // check anyway in case someone set the limit stupidly low.
740  $fit = true;
741 
742  $values = $pageSet->getNormalizedTitlesAsResult( $result );
743  if ( $values ) {
744  // @phan-suppress-next-line PhanRedundantCondition
745  $fit = $fit && $result->addValue( 'query', 'normalized', $values );
746  }
747  $values = $pageSet->getConvertedTitlesAsResult( $result );
748  if ( $values ) {
749  $fit = $fit && $result->addValue( 'query', 'converted', $values );
750  }
751  $values = $pageSet->getInterwikiTitlesAsResult( $result, $this->mParams['iwurl'] );
752  if ( $values ) {
753  $fit = $fit && $result->addValue( 'query', 'interwiki', $values );
754  }
755  $values = $pageSet->getRedirectTitlesAsResult( $result );
756  if ( $values ) {
757  $fit = $fit && $result->addValue( 'query', 'redirects', $values );
758  }
759  $values = $pageSet->getMissingRevisionIDsAsResult( $result );
760  if ( $values ) {
761  $fit = $fit && $result->addValue( 'query', 'badrevids', $values );
762  }
763 
764  // Page elements
765  $pages = [];
766 
767  // Report any missing titles
768  foreach ( $pageSet->getMissingTitles() as $fakeId => $title ) {
769  $vals = [];
771  $vals['missing'] = true;
772  if ( $title->isKnown() ) {
773  $vals['known'] = true;
774  }
775  $pages[$fakeId] = $vals;
776  }
777  // Report any invalid titles
778  foreach ( $pageSet->getInvalidTitlesAndReasons() as $fakeId => $data ) {
779  $pages[$fakeId] = $data + [ 'invalid' => true ];
780  }
781  // Report any missing page ids
782  foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
783  $pages[$pageid] = [
784  'pageid' => $pageid,
785  'missing' => true,
786  ];
787  }
788  // Report special pages
790  foreach ( $pageSet->getSpecialTitles() as $fakeId => $title ) {
791  $vals = [];
793  $vals['special'] = true;
794  if ( !$title->isKnown() ) {
795  $vals['missing'] = true;
796  }
797  $pages[$fakeId] = $vals;
798  }
799 
800  // Output general page information for found titles
801  foreach ( $pageSet->getGoodTitles() as $pageid => $title ) {
802  $vals = [];
803  $vals['pageid'] = $pageid;
805  $pages[$pageid] = $vals;
806  }
807 
808  if ( count( $pages ) ) {
809  $pageSet->populateGeneratorData( $pages );
810  ApiResult::setArrayType( $pages, 'BCarray' );
811 
812  if ( $this->mParams['indexpageids'] ) {
813  $pageIDs = array_keys( ApiResult::stripMetadataNonRecursive( $pages ) );
814  // json treats all map keys as strings - converting to match
815  $pageIDs = array_map( 'strval', $pageIDs );
816  ApiResult::setIndexedTagName( $pageIDs, 'id' );
817  $fit = $fit && $result->addValue( 'query', 'pageids', $pageIDs );
818  }
819 
820  ApiResult::setIndexedTagName( $pages, 'page' );
821  $fit = $fit && $result->addValue( 'query', 'pages', $pages );
822  }
823 
824  if ( !$fit ) {
825  $this->dieWithError( 'apierror-badconfig-resulttoosmall', 'badconfig' );
826  }
827 
828  if ( $this->mParams['export'] ) {
829  $this->doExport( $pageSet, $result );
830  }
831  }
832 
837  private function doExport( $pageSet, $result ) {
838  $exportTitles = [];
839  $titles = $pageSet->getGoodPages();
840  if ( count( $titles ) ) {
842  foreach ( $titles as $title ) {
843  if ( $this->getAuthority()->authorizeRead( 'read', $title ) ) {
844  $exportTitles[] = $title;
845  }
846  }
847  }
848 
849  $exporter = $this->wikiExporterFactory->getWikiExporter( $this->getDB() );
850  $sink = new DumpStringOutput;
851  $exporter->setOutputSink( $sink );
852  $exporter->setSchemaVersion( $this->mParams['exportschema'] );
853  $exporter->openStream();
854  foreach ( $exportTitles as $title ) {
855  $exporter->pageByTitle( $title );
856  }
857  $exporter->closeStream();
858 
859  // Don't check the size of exported stuff
860  // It's not continuable, so it would cause more
861  // problems than it'd solve
862  if ( $this->mParams['exportnowrap'] ) {
863  $result->reset();
864  // Raw formatter will handle this
865  $result->addValue( null, 'text', $sink, ApiResult::NO_SIZE_CHECK );
866  $result->addValue( null, 'mime', 'text/xml', ApiResult::NO_SIZE_CHECK );
867  $result->addValue( null, 'filename', 'export.xml', ApiResult::NO_SIZE_CHECK );
868  } else {
869  $result->addValue( 'query', 'export', $sink, ApiResult::NO_SIZE_CHECK );
870  $result->addValue( 'query', ApiResult::META_BC_SUBELEMENTS, [ 'export' ] );
871  }
872  }
873 
874  public function getAllowedParams( $flags = 0 ) {
875  $result = [
876  'prop' => [
877  ParamValidator::PARAM_ISMULTI => true,
878  ParamValidator::PARAM_TYPE => 'submodule',
879  ],
880  'list' => [
881  ParamValidator::PARAM_ISMULTI => true,
882  ParamValidator::PARAM_TYPE => 'submodule',
883  ],
884  'meta' => [
885  ParamValidator::PARAM_ISMULTI => true,
886  ParamValidator::PARAM_TYPE => 'submodule',
887  ],
888  'indexpageids' => false,
889  'export' => false,
890  'exportnowrap' => false,
891  'exportschema' => [
892  ParamValidator::PARAM_DEFAULT => WikiExporter::schemaVersion(),
893  ParamValidator::PARAM_TYPE => XmlDumpWriter::$supportedSchemas,
894  ],
895  'iwurl' => false,
896  'continue' => [
897  ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
898  ],
899  'rawcontinue' => false,
900  ];
901  if ( $flags ) {
902  $result += $this->getPageSet()->getFinalParams( $flags );
903  }
904 
905  return $result;
906  }
907 
908  public function isReadMode() {
909  // We need to make an exception for certain meta modules that should be
910  // accessible even without the 'read' right. Restrict the exception as
911  // much as possible: no other modules allowed, and no pageset
912  // parameters either. We do allow the 'rawcontinue' and 'indexpageids'
913  // parameters since frameworks might add these unconditionally and they
914  // can't expose anything here.
915  $allowedParams = [ 'rawcontinue' => 1, 'indexpageids' => 1 ];
916  $this->mParams = $this->extractRequestParams();
917  $request = $this->getRequest();
918  foreach ( $this->mParams + $this->getPageSet()->extractRequestParams() as $param => $value ) {
919  $needed = $param === 'meta';
920  if ( !isset( $allowedParams[$param] ) && $request->getCheck( $param ) !== $needed ) {
921  return true;
922  }
923  }
924 
925  // Ask each module if it requires read mode. Any true => this returns
926  // true.
927  $modules = [];
928  $this->instantiateModules( $modules, 'meta' );
929  foreach ( $modules as $module ) {
930  if ( $module->isReadMode() ) {
931  return true;
932  }
933  }
934 
935  return false;
936  }
937 
938  protected function getExamplesMessages() {
939  return [
940  'action=query&prop=revisions&meta=siteinfo&' .
941  'titles=Main%20Page&rvprop=user|comment&continue='
942  => 'apihelp-query-example-revisions',
943  'action=query&generator=allpages&gapprefix=API/&prop=revisions&continue='
944  => 'apihelp-query-example-allpages',
945  ];
946  }
947 
948  public function getHelpUrls() {
949  return [
950  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Query',
951  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Meta',
952  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Properties',
953  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Lists',
954  ];
955  }
956 }
$modules
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:56
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
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1458
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:1663
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.
Definition: ApiPageSet.php:50
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:908
const QUERY_PROP_MODULES
List of Api Query prop modules.
Definition: ApiQuery.php:46
instantiateModules(&$modules, $param)
Create instances of all modules requested by the client.
Definition: ApiQuery.php:710
mergeCacheMode( $cacheMode, $modCacheMode)
Update a cache mode string, applying the cache mode of a new module to it.
Definition: ApiQuery.php:691
getAllowedParams( $flags=0)
Definition: ApiQuery.php:874
getModuleManager()
Overrides to return this instance's module manager.
Definition: ApiQuery.php:564
ApiPageSet $mPageSet
Definition: ApiQuery.php:510
const QUERY_META_MODULES
List of Api Query meta modules.
Definition: ApiQuery.php:441
outputGeneralPageInfo()
Appends an element for each page in the current pageSet with the most general information (id,...
Definition: ApiQuery.php:734
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiQuery.php:938
__construct(ApiMain $main, $action, ObjectFactory $objectFactory, ILoadBalancer $loadBalancer, WikiExporterFactory $wikiExporterFactory)
Definition: ApiQuery.php:529
doExport( $pageSet, $result)
Definition: ApiQuery.php:837
const QUERY_LIST_MODULES
List of Api Query list modules.
Definition: ApiQuery.php:197
ILoadBalancer $loadBalancer
Definition: ApiQuery.php:517
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiQuery.php:948
getPageSet()
Gets the set of pages the user has requested (or generated)
Definition: ApiQuery.php:590
execute()
Query execution happens in the following steps: #1 Create a PageSet object with any pages requested b...
Definition: ApiQuery.php:619
WikiExporterFactory $wikiExporterFactory
Definition: ApiQuery.php:520
getNamedDB( $name, $db, $groups)
Get the query database connection with the given name.
Definition: ApiQuery.php:578
getCustomPrinter()
Definition: ApiQuery.php:597
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.
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:39
Database cluster connection, tracking, load balancing, and transaction manager interface.
return true
Definition: router.php:90