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  '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,
685  }
686  $data = $continuationManager->getRawContinuation();
687  if ( $data ) {
688  $this->getResult()->addValue( null, 'query-continue', $data,
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  return [
954  'action=query&prop=revisions&meta=siteinfo&' .
955  'titles=Main%20Page&rvprop=user|comment&continue='
956  => 'apihelp-query-example-revisions',
957  'action=query&generator=allpages&gapprefix=API/&prop=revisions&continue='
958  => 'apihelp-query-example-allpages',
959  ];
960  }
961 
962  public function getHelpUrls() {
963  return [
964  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Query',
965  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Meta',
966  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Properties',
967  'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Lists',
968  ];
969  }
970 }
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:56
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition: ApiBase.php:1453
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:1627
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1689
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: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:962
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 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
Create and track the database connections and transactions for a given database cluster.
return true
Definition: router.php:90