MediaWiki  master
ApiQueryInfo.php
Go to the documentation of this file.
1 <?php
27 
33 class ApiQueryInfo extends ApiQueryBase {
34 
40  private $namespaceInfo;
42  private $titleFactory;
45 
46  private $fld_protection = false, $fld_talkid = false,
47  $fld_subjectid = false, $fld_url = false,
48  $fld_readable = false, $fld_watched = false,
52 
57  private $fld_linkclasses = false;
58 
59  private $params;
60 
62  private $titles;
64  private $missing;
66  private $everything;
67 
70 
73 
79 
84  private $linkClasses;
85 
86  private $showZeroWatchers = false;
87 
88  private $tokenFunctions;
89 
90  private $countTestedActions = 0;
91 
101  public function __construct(
102  ApiQuery $queryModule,
103  $moduleName,
109  ) {
110  parent::__construct( $queryModule, $moduleName, 'in' );
111  $this->contentLanguage = $contentLanguage;
112  $this->linkBatchFactory = $linkBatchFactory;
113  $this->namespaceInfo = $namespaceInfo;
114  $this->titleFactory = $titleFactory;
115  $this->watchedItemStore = $watchedItemStore;
116  }
117 
122  public function requestExtraData( $pageSet ) {
123  $pageSet->requestField( 'page_restrictions' );
124  // If the pageset is resolving redirects we won't get page_is_redirect.
125  // But we can't know for sure until the pageset is executed (revids may
126  // turn it off), so request it unconditionally.
127  $pageSet->requestField( 'page_is_redirect' );
128  $pageSet->requestField( 'page_is_new' );
129  $config = $this->getConfig();
130  $pageSet->requestField( 'page_touched' );
131  $pageSet->requestField( 'page_latest' );
132  $pageSet->requestField( 'page_len' );
133  $pageSet->requestField( 'page_content_model' );
134  if ( $config->get( 'PageLanguageUseDB' ) ) {
135  $pageSet->requestField( 'page_lang' );
136  }
137  }
138 
146  protected function getTokenFunctions() {
147  // Don't call the hooks twice
148  if ( isset( $this->tokenFunctions ) ) {
149  return $this->tokenFunctions;
150  }
151 
152  // If we're in a mode that breaks the same-origin policy, no tokens can
153  // be obtained
154  if ( $this->lacksSameOriginSecurity() ) {
155  return [];
156  }
157 
158  $this->tokenFunctions = [
159  'edit' => [ self::class, 'getEditToken' ],
160  'delete' => [ self::class, 'getDeleteToken' ],
161  'protect' => [ self::class, 'getProtectToken' ],
162  'move' => [ self::class, 'getMoveToken' ],
163  'block' => [ self::class, 'getBlockToken' ],
164  'unblock' => [ self::class, 'getUnblockToken' ],
165  'email' => [ self::class, 'getEmailToken' ],
166  'import' => [ self::class, 'getImportToken' ],
167  'watch' => [ self::class, 'getWatchToken' ],
168  ];
169 
170  return $this->tokenFunctions;
171  }
172 
174  protected static $cachedTokens = [];
175 
179  public static function resetTokenCache() {
180  self::$cachedTokens = [];
181  }
182 
192  private static function getUserToken( User $user, string $right ) {
193  if ( !MediaWikiServices::getInstance()
195  ->userHasRight( $user, $right )
196  ) {
197  return false;
198  }
199 
200  // The token is always the same, let's exploit that
201  if ( !isset( self::$cachedTokens['edit'] ) ) {
202  self::$cachedTokens['edit'] = $user->getEditToken();
203  }
204 
205  return self::$cachedTokens['edit'];
206  }
207 
213  public static function getEditToken( User $user ) {
214  return self::getUserToken( $user, 'edit' );
215  }
216 
222  public static function getDeleteToken( User $user ) {
223  return self::getUserToken( $user, 'delete' );
224  }
225 
231  public static function getProtectToken( User $user ) {
232  return self::getUserToken( $user, 'protect' );
233  }
234 
240  public static function getMoveToken( User $user ) {
241  return self::getUserToken( $user, 'move' );
242  }
243 
249  public static function getBlockToken( User $user ) {
250  return self::getUserToken( $user, 'block' );
251  }
252 
258  public static function getUnblockToken( User $user ) {
259  // Currently, this is exactly the same as the block token
260  return self::getBlockToken( $user );
261  }
262 
268  public static function getEmailToken( User $user ) {
269  if ( !$user->canSendEmail() || $user->isBlockedFromEmailuser() ) {
270  return false;
271  }
272 
273  // The token is always the same, let's exploit that
274  if ( !isset( self::$cachedTokens['email'] ) ) {
275  self::$cachedTokens['email'] = $user->getEditToken();
276  }
277 
278  return self::$cachedTokens['email'];
279  }
280 
286  public static function getImportToken( User $user ) {
287  if ( !MediaWikiServices::getInstance()
289  ->userHasAnyRight( $user, 'import', 'importupload' ) ) {
290  return false;
291  }
292 
293  // The token is always the same, let's exploit that
294  if ( !isset( self::$cachedTokens['import'] ) ) {
295  self::$cachedTokens['import'] = $user->getEditToken();
296  }
297 
298  return self::$cachedTokens['import'];
299  }
300 
306  public static function getWatchToken( User $user ) {
307  if ( !$user->isRegistered() ) {
308  return false;
309  }
310 
311  // The token is always the same, let's exploit that
312  if ( !isset( self::$cachedTokens['watch'] ) ) {
313  self::$cachedTokens['watch'] = $user->getEditToken( 'watch' );
314  }
315 
316  return self::$cachedTokens['watch'];
317  }
318 
324  public static function getOptionsToken( User $user ) {
325  if ( !$user->isRegistered() ) {
326  return false;
327  }
328 
329  // The token is always the same, let's exploit that
330  if ( !isset( self::$cachedTokens['options'] ) ) {
331  self::$cachedTokens['options'] = $user->getEditToken();
332  }
333 
334  return self::$cachedTokens['options'];
335  }
336 
337  public function execute() {
338  $this->params = $this->extractRequestParams();
339  if ( $this->params['prop'] !== null ) {
340  $prop = array_flip( $this->params['prop'] );
341  $this->fld_protection = isset( $prop['protection'] );
342  $this->fld_watched = isset( $prop['watched'] );
343  $this->fld_watchers = isset( $prop['watchers'] );
344  $this->fld_visitingwatchers = isset( $prop['visitingwatchers'] );
345  $this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] );
346  $this->fld_talkid = isset( $prop['talkid'] );
347  $this->fld_subjectid = isset( $prop['subjectid'] );
348  $this->fld_url = isset( $prop['url'] );
349  $this->fld_readable = isset( $prop['readable'] );
350  $this->fld_preload = isset( $prop['preload'] );
351  $this->fld_displaytitle = isset( $prop['displaytitle'] );
352  $this->fld_varianttitles = isset( $prop['varianttitles'] );
353  $this->fld_linkclasses = isset( $prop['linkclasses'] );
354  }
355 
356  $pageSet = $this->getPageSet();
357  $this->titles = $pageSet->getGoodTitles();
358  $this->missing = $pageSet->getMissingTitles();
359  $this->everything = $this->titles + $this->missing;
360  $result = $this->getResult();
361 
362  uasort( $this->everything, [ Title::class, 'compare' ] );
363  if ( $this->params['continue'] !== null ) {
364  // Throw away any titles we're gonna skip so they don't
365  // clutter queries
366  $cont = explode( '|', $this->params['continue'] );
367  $this->dieContinueUsageIf( count( $cont ) != 2 );
368  $conttitle = $this->titleFactory->makeTitleSafe( $cont[0], $cont[1] );
369  foreach ( $this->everything as $pageid => $title ) {
370  if ( Title::compare( $title, $conttitle ) >= 0 ) {
371  break;
372  }
373  unset( $this->titles[$pageid] );
374  unset( $this->missing[$pageid] );
375  unset( $this->everything[$pageid] );
376  }
377  }
378 
379  $this->pageRestrictions = $pageSet->getCustomField( 'page_restrictions' );
380  // when resolving redirects, no page will have this field
381  $this->pageIsRedir = !$pageSet->isResolvingRedirects()
382  ? $pageSet->getCustomField( 'page_is_redirect' )
383  : [];
384  $this->pageIsNew = $pageSet->getCustomField( 'page_is_new' );
385 
386  $this->pageTouched = $pageSet->getCustomField( 'page_touched' );
387  $this->pageLatest = $pageSet->getCustomField( 'page_latest' );
388  $this->pageLength = $pageSet->getCustomField( 'page_len' );
389 
390  // Get protection info if requested
391  if ( $this->fld_protection ) {
392  $this->getProtectionInfo();
393  }
394 
395  if ( $this->fld_watched || $this->fld_notificationtimestamp ) {
396  $this->getWatchedInfo();
397  }
398 
399  if ( $this->fld_watchers ) {
400  $this->getWatcherInfo();
401  }
402 
403  if ( $this->fld_visitingwatchers ) {
404  $this->getVisitingWatcherInfo();
405  }
406 
407  // Run the talkid/subjectid query if requested
408  if ( $this->fld_talkid || $this->fld_subjectid ) {
409  $this->getTSIDs();
410  }
411 
412  if ( $this->fld_displaytitle ) {
413  $this->getDisplayTitle();
414  }
415 
416  if ( $this->fld_varianttitles ) {
417  $this->getVariantTitles();
418  }
419 
420  if ( $this->fld_linkclasses ) {
421  $this->getLinkClasses( $this->params['linkcontext'] );
422  }
423 
425  foreach ( $this->everything as $pageid => $title ) {
426  $pageInfo = $this->extractPageInfo( $pageid, $title );
427  $fit = $pageInfo !== null && $result->addValue( [
428  'query',
429  'pages'
430  ], $pageid, $pageInfo );
431  if ( !$fit ) {
432  $this->setContinueEnumParameter( 'continue',
433  $title->getNamespace() . '|' .
434  $title->getText() );
435  break;
436  }
437  }
438  }
439 
446  private function extractPageInfo( $pageid, $title ) {
447  $pageInfo = [];
448  // $title->exists() needs pageid, which is not set for all title objects
449  $titleExists = $pageid > 0;
450  $ns = $title->getNamespace();
451  $dbkey = $title->getDBkey();
452 
453  $pageInfo['contentmodel'] = $title->getContentModel();
454 
455  $pageLanguage = $title->getPageLanguage();
456  $pageInfo['pagelanguage'] = $pageLanguage->getCode();
457  $pageInfo['pagelanguagehtmlcode'] = $pageLanguage->getHtmlCode();
458  $pageInfo['pagelanguagedir'] = $pageLanguage->getDir();
459 
460  $user = $this->getUser();
461 
462  if ( $titleExists ) {
463  $pageInfo['touched'] = wfTimestamp( TS_ISO_8601, $this->pageTouched[$pageid] );
464  $pageInfo['lastrevid'] = (int)$this->pageLatest[$pageid];
465  $pageInfo['length'] = (int)$this->pageLength[$pageid];
466 
467  if ( isset( $this->pageIsRedir[$pageid] ) && $this->pageIsRedir[$pageid] ) {
468  $pageInfo['redirect'] = true;
469  }
470  if ( $this->pageIsNew[$pageid] ) {
471  $pageInfo['new'] = true;
472  }
473  }
474 
475  if ( $this->params['token'] !== null ) {
477  $pageInfo['starttimestamp'] = wfTimestamp( TS_ISO_8601, time() );
478  foreach ( $this->params['token'] as $t ) {
479  $val = call_user_func( $tokenFunctions[$t], $this->getUser() );
480  if ( $val === false ) {
481  $this->addWarning( [ 'apiwarn-tokennotallowed', $t ] );
482  } else {
483  $pageInfo[$t . 'token'] = $val;
484  }
485  }
486  }
487 
488  if ( $this->fld_protection ) {
489  $pageInfo['protection'] = [];
490  if ( isset( $this->protections[$ns][$dbkey] ) ) {
491  $pageInfo['protection'] =
492  $this->protections[$ns][$dbkey];
493  }
494  ApiResult::setIndexedTagName( $pageInfo['protection'], 'pr' );
495 
496  $pageInfo['restrictiontypes'] = [];
497  if ( isset( $this->restrictionTypes[$ns][$dbkey] ) ) {
498  $pageInfo['restrictiontypes'] =
499  $this->restrictionTypes[$ns][$dbkey];
500  }
501  ApiResult::setIndexedTagName( $pageInfo['restrictiontypes'], 'rt' );
502  }
503 
504  if ( $this->fld_watched ) {
505  $pageInfo['watched'] = false;
506 
507  if ( isset( $this->watched[$ns][$dbkey] ) ) {
508  $pageInfo['watched'] = $this->watched[$ns][$dbkey];
509  }
510 
511  if ( isset( $this->watchlistExpiries[$ns][$dbkey] ) ) {
512  $pageInfo['watchlistexpiry'] = $this->watchlistExpiries[$ns][$dbkey];
513  }
514  }
515 
516  if ( $this->fld_watchers ) {
517  if ( $this->watchers !== null && $this->watchers[$ns][$dbkey] !== 0 ) {
518  $pageInfo['watchers'] = $this->watchers[$ns][$dbkey];
519  } elseif ( $this->showZeroWatchers ) {
520  $pageInfo['watchers'] = 0;
521  }
522  }
523 
524  if ( $this->fld_visitingwatchers ) {
525  if ( $this->visitingwatchers !== null && $this->visitingwatchers[$ns][$dbkey] !== 0 ) {
526  $pageInfo['visitingwatchers'] = $this->visitingwatchers[$ns][$dbkey];
527  } elseif ( $this->showZeroWatchers ) {
528  $pageInfo['visitingwatchers'] = 0;
529  }
530  }
531 
532  if ( $this->fld_notificationtimestamp ) {
533  $pageInfo['notificationtimestamp'] = '';
534  if ( isset( $this->notificationtimestamps[$ns][$dbkey] ) ) {
535  $pageInfo['notificationtimestamp'] =
536  wfTimestamp( TS_ISO_8601, $this->notificationtimestamps[$ns][$dbkey] );
537  }
538  }
539 
540  if ( $this->fld_talkid && isset( $this->talkids[$ns][$dbkey] ) ) {
541  $pageInfo['talkid'] = $this->talkids[$ns][$dbkey];
542  }
543 
544  if ( $this->fld_subjectid && isset( $this->subjectids[$ns][$dbkey] ) ) {
545  $pageInfo['subjectid'] = $this->subjectids[$ns][$dbkey];
546  }
547 
548  if ( $this->fld_url ) {
549  $pageInfo['fullurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
550  $pageInfo['editurl'] = wfExpandUrl( $title->getFullURL( 'action=edit' ), PROTO_CURRENT );
551  $pageInfo['canonicalurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CANONICAL );
552  }
553  if ( $this->fld_readable ) {
554  $pageInfo['readable'] = $this->getPermissionManager()->userCan(
555  'read', $user, $title
556  );
557  }
558 
559  if ( $this->fld_preload ) {
560  if ( $titleExists ) {
561  $pageInfo['preload'] = '';
562  } else {
563  $text = null;
564  $this->getHookRunner()->onEditFormPreloadText( $text, $title );
565 
566  $pageInfo['preload'] = $text;
567  }
568  }
569 
570  if ( $this->fld_displaytitle ) {
571  if ( isset( $this->displaytitles[$pageid] ) ) {
572  $pageInfo['displaytitle'] = $this->displaytitles[$pageid];
573  } else {
574  $pageInfo['displaytitle'] = $title->getPrefixedText();
575  }
576  }
577 
578  if ( $this->fld_varianttitles && isset( $this->variantTitles[$pageid] ) ) {
579  $pageInfo['varianttitles'] = $this->variantTitles[$pageid];
580  }
581 
582  if ( $this->fld_linkclasses && isset( $this->linkClasses[$pageid] ) ) {
583  $pageInfo['linkclasses'] = $this->linkClasses[$pageid];
584  }
585 
586  if ( $this->params['testactions'] ) {
587  $limit = $this->getMain()->canApiHighLimits() ? self::LIMIT_SML2 : self::LIMIT_SML1;
588  if ( $this->countTestedActions >= $limit ) {
589  return null; // force a continuation
590  }
591 
592  $detailLevel = $this->params['testactionsdetail'];
593  $rigor = $detailLevel === 'quick'
594  ? PermissionManager::RIGOR_QUICK
595  // Not using RIGOR_SECURE here, because that results in master connection
596  : PermissionManager::RIGOR_FULL;
597  $errorFormatter = $this->getErrorFormatter();
598  if ( $errorFormatter->getFormat() === 'bc' ) {
599  // Eew, no. Use a more modern format here.
600  $errorFormatter = $errorFormatter->newWithFormat( 'plaintext' );
601  }
602 
603  $user = $this->getUser();
604  $pageInfo['actions'] = [];
605  foreach ( $this->params['testactions'] as $action ) {
606  $this->countTestedActions++;
607 
608  if ( $detailLevel === 'boolean' ) {
609  $pageInfo['actions'][$action] = $this->getPermissionManager()->userCan(
610  $action, $user, $title
611  );
612  } else {
613  $pageInfo['actions'][$action] = $errorFormatter->arrayFromStatus( $this->errorArrayToStatus(
614  $this->getPermissionManager()->getPermissionErrors(
615  $action, $user, $title, $rigor
616  ),
617  $user
618  ) );
619  }
620  }
621  }
622 
623  return $pageInfo;
624  }
625 
629  private function getProtectionInfo() {
630  $this->protections = [];
631  $db = $this->getDB();
632 
633  // Get normal protections for existing titles
634  if ( count( $this->titles ) ) {
635  $this->resetQueryParams();
636  $this->addTables( 'page_restrictions' );
637  $this->addFields( [ 'pr_page', 'pr_type', 'pr_level',
638  'pr_expiry', 'pr_cascade' ] );
639  $this->addWhereFld( 'pr_page', array_keys( $this->titles ) );
640 
641  $res = $this->select( __METHOD__ );
642  foreach ( $res as $row ) {
644  $title = $this->titles[$row->pr_page];
645  $a = [
646  'type' => $row->pr_type,
647  'level' => $row->pr_level,
648  'expiry' => ApiResult::formatExpiry( $row->pr_expiry )
649  ];
650  if ( $row->pr_cascade ) {
651  $a['cascade'] = true;
652  }
653  $this->protections[$title->getNamespace()][$title->getDBkey()][] = $a;
654  }
655  // Also check old restrictions
656  foreach ( $this->titles as $pageId => $title ) {
657  if ( $this->pageRestrictions[$pageId] ) {
658  $namespace = $title->getNamespace();
659  $dbKey = $title->getDBkey();
660  $restrictions = explode( ':', trim( $this->pageRestrictions[$pageId] ) );
661  foreach ( $restrictions as $restrict ) {
662  $temp = explode( '=', trim( $restrict ) );
663  if ( count( $temp ) == 1 ) {
664  // old old format should be treated as edit/move restriction
665  $restriction = trim( $temp[0] );
666 
667  if ( $restriction == '' ) {
668  continue;
669  }
670  $this->protections[$namespace][$dbKey][] = [
671  'type' => 'edit',
672  'level' => $restriction,
673  'expiry' => 'infinity',
674  ];
675  $this->protections[$namespace][$dbKey][] = [
676  'type' => 'move',
677  'level' => $restriction,
678  'expiry' => 'infinity',
679  ];
680  } else {
681  $restriction = trim( $temp[1] );
682  if ( $restriction == '' ) {
683  continue;
684  }
685  $this->protections[$namespace][$dbKey][] = [
686  'type' => $temp[0],
687  'level' => $restriction,
688  'expiry' => 'infinity',
689  ];
690  }
691  }
692  }
693  }
694  }
695 
696  // Get protections for missing titles
697  if ( count( $this->missing ) ) {
698  $this->resetQueryParams();
699  $lb = $this->linkBatchFactory->newLinkBatch( $this->missing );
700  $this->addTables( 'protected_titles' );
701  $this->addFields( [ 'pt_title', 'pt_namespace', 'pt_create_perm', 'pt_expiry' ] );
702  $this->addWhere( $lb->constructSet( 'pt', $db ) );
703  $res = $this->select( __METHOD__ );
704  foreach ( $res as $row ) {
705  $this->protections[$row->pt_namespace][$row->pt_title][] = [
706  'type' => 'create',
707  'level' => $row->pt_create_perm,
708  'expiry' => ApiResult::formatExpiry( $row->pt_expiry )
709  ];
710  }
711  }
712 
713  // Separate good and missing titles into files and other pages
714  // and populate $this->restrictionTypes
715  $images = $others = [];
716  foreach ( $this->everything as $title ) {
717  if ( $title->getNamespace() === NS_FILE ) {
718  $images[] = $title->getDBkey();
719  } else {
720  $others[] = $title;
721  }
722  // Applicable protection types
723  $this->restrictionTypes[$title->getNamespace()][$title->getDBkey()] =
724  array_values( $title->getRestrictionTypes() );
725  }
726 
727  if ( count( $others ) ) {
728  // Non-images: check templatelinks
729  $lb = $this->linkBatchFactory->newLinkBatch( $others );
730  $this->resetQueryParams();
731  $this->addTables( [ 'page_restrictions', 'page', 'templatelinks' ] );
732  $this->addFields( [ 'pr_type', 'pr_level', 'pr_expiry',
733  'page_title', 'page_namespace',
734  'tl_title', 'tl_namespace' ] );
735  $this->addWhere( $lb->constructSet( 'tl', $db ) );
736  $this->addWhere( 'pr_page = page_id' );
737  $this->addWhere( 'pr_page = tl_from' );
738  $this->addWhereFld( 'pr_cascade', 1 );
739 
740  $res = $this->select( __METHOD__ );
741  foreach ( $res as $row ) {
742  $source = $this->titleFactory->makeTitle( $row->page_namespace, $row->page_title );
743  $this->protections[$row->tl_namespace][$row->tl_title][] = [
744  'type' => $row->pr_type,
745  'level' => $row->pr_level,
746  'expiry' => ApiResult::formatExpiry( $row->pr_expiry ),
747  'source' => $source->getPrefixedText()
748  ];
749  }
750  }
751 
752  if ( count( $images ) ) {
753  // Images: check imagelinks
754  $this->resetQueryParams();
755  $this->addTables( [ 'page_restrictions', 'page', 'imagelinks' ] );
756  $this->addFields( [ 'pr_type', 'pr_level', 'pr_expiry',
757  'page_title', 'page_namespace', 'il_to' ] );
758  $this->addWhere( 'pr_page = page_id' );
759  $this->addWhere( 'pr_page = il_from' );
760  $this->addWhereFld( 'pr_cascade', 1 );
761  $this->addWhereFld( 'il_to', $images );
762 
763  $res = $this->select( __METHOD__ );
764  foreach ( $res as $row ) {
765  $source = $this->titleFactory->makeTitle( $row->page_namespace, $row->page_title );
766  $this->protections[NS_FILE][$row->il_to][] = [
767  'type' => $row->pr_type,
768  'level' => $row->pr_level,
769  'expiry' => ApiResult::formatExpiry( $row->pr_expiry ),
770  'source' => $source->getPrefixedText()
771  ];
772  }
773  }
774  }
775 
780  private function getTSIDs() {
781  $getTitles = $this->talkids = $this->subjectids = [];
782  $nsInfo = $this->namespaceInfo;
783 
785  foreach ( $this->everything as $t ) {
786  if ( $nsInfo->isTalk( $t->getNamespace() ) ) {
787  if ( $this->fld_subjectid ) {
788  $getTitles[] = $t->getSubjectPage();
789  }
790  } elseif ( $this->fld_talkid ) {
791  $getTitles[] = $t->getTalkPage();
792  }
793  }
794  if ( $getTitles === [] ) {
795  return;
796  }
797 
798  $db = $this->getDB();
799 
800  // Construct a custom WHERE clause that matches
801  // all titles in $getTitles
802  $lb = $this->linkBatchFactory->newLinkBatch( $getTitles );
803  $this->resetQueryParams();
804  $this->addTables( 'page' );
805  $this->addFields( [ 'page_title', 'page_namespace', 'page_id' ] );
806  $this->addWhere( $lb->constructSet( 'page', $db ) );
807  $res = $this->select( __METHOD__ );
808  foreach ( $res as $row ) {
809  if ( $nsInfo->isTalk( $row->page_namespace ) ) {
810  $this->talkids[$nsInfo->getSubject( $row->page_namespace )][$row->page_title] =
811  (int)( $row->page_id );
812  } else {
813  $this->subjectids[$nsInfo->getTalk( $row->page_namespace )][$row->page_title] =
814  (int)( $row->page_id );
815  }
816  }
817  }
818 
819  private function getDisplayTitle() {
820  $this->displaytitles = [];
821 
822  $pageIds = array_keys( $this->titles );
823 
824  if ( $pageIds === [] ) {
825  return;
826  }
827 
828  $this->resetQueryParams();
829  $this->addTables( 'page_props' );
830  $this->addFields( [ 'pp_page', 'pp_value' ] );
831  $this->addWhereFld( 'pp_page', $pageIds );
832  $this->addWhereFld( 'pp_propname', 'displaytitle' );
833  $res = $this->select( __METHOD__ );
834 
835  foreach ( $res as $row ) {
836  $this->displaytitles[$row->pp_page] = $row->pp_value;
837  }
838  }
839 
847  private function getLinkClasses( ?LinkTarget $context_title = null ) {
848  if ( $this->titles === [] ) {
849  return;
850  }
851  // For compatibility with legacy GetLinkColours hook:
852  // $pagemap maps from page id to title (as prefixed db key)
853  // $classes maps from title (prefixed db key) to a space-separated
854  // list of link classes ("link colours").
855  // The hook should not modify $pagemap, and should only append to
856  // $classes (being careful to maintain space separation).
857  $classes = [];
858  $pagemap = [];
859  foreach ( $this->titles as $pageId => $title ) {
860  $pdbk = $title->getPrefixedDBkey();
861  $pagemap[$pageId] = $pdbk;
862  $classes[$pdbk] = $title->isRedirect() ? 'mw-redirect' : '';
863  }
864  // legacy hook requires a real Title, not a LinkTarget
865  $context_title = $this->titleFactory->newFromLinkTarget(
866  $context_title ?? $this->titleFactory->newMainPage()
867  );
868  $this->getHookRunner()->onGetLinkColours(
869  $pagemap, $classes, $context_title
870  );
871 
872  // This API class expects the class list to be:
873  // (a) indexed by pageid, not title, and
874  // (b) a proper array of strings (possibly zero-length),
875  // not a single space-separated string (possibly the empty string)
876  $this->linkClasses = [];
877  foreach ( $this->titles as $pageId => $title ) {
878  $pdbk = $title->getPrefixedDBkey();
879  $this->linkClasses[$pageId] = preg_split(
880  '/\s+/', $classes[$pdbk] ?? '', -1, PREG_SPLIT_NO_EMPTY
881  );
882  }
883  }
884 
885  private function getVariantTitles() {
886  if ( $this->titles === [] ) {
887  return;
888  }
889  $this->variantTitles = [];
890  foreach ( $this->titles as $pageId => $t ) {
891  $this->variantTitles[$pageId] = isset( $this->displaytitles[$pageId] )
892  ? $this->getAllVariants( $this->displaytitles[$pageId] )
893  : $this->getAllVariants( $t->getText(), $t->getNamespace() );
894  }
895  }
896 
897  private function getAllVariants( $text, $ns = NS_MAIN ) {
898  $result = [];
899  $contLang = $this->contentLanguage;
900  foreach ( $contLang->getVariants() as $variant ) {
901  $convertTitle = $contLang->autoConvert( $text, $variant );
902  if ( $ns !== NS_MAIN ) {
903  $convertNs = $contLang->convertNamespace( $ns, $variant );
904  $convertTitle = $convertNs . ':' . $convertTitle;
905  }
906  $result[$variant] = $convertTitle;
907  }
908  return $result;
909  }
910 
915  private function getWatchedInfo() {
916  $user = $this->getUser();
917 
918  if ( $user->isAnon() || count( $this->everything ) == 0
919  || !$this->getPermissionManager()->userHasRight( $user, 'viewmywatchlist' )
920  ) {
921  return;
922  }
923 
924  $this->watched = [];
925  $this->watchlistExpiries = [];
926  $this->notificationtimestamps = [];
927 
929  $items = $this->watchedItemStore->loadWatchedItemsBatch( $user, $this->everything );
930 
931  foreach ( $items as $item ) {
932  $nsId = $item->getLinkTarget()->getNamespace();
933  $dbKey = $item->getLinkTarget()->getDBkey();
934 
935  if ( $this->fld_watched ) {
936  $this->watched[$nsId][$dbKey] = true;
937 
938  $expiry = $item->getExpiry( TS_ISO_8601 );
939  if ( $expiry ) {
940  $this->watchlistExpiries[$nsId][$dbKey] = $expiry;
941  }
942  }
943 
944  if ( $this->fld_notificationtimestamp ) {
945  $this->notificationtimestamps[$nsId][$dbKey] = $item->getNotificationTimestamp();
946  }
947  }
948  }
949 
953  private function getWatcherInfo() {
954  if ( count( $this->everything ) == 0 ) {
955  return;
956  }
957 
958  $user = $this->getUser();
959  $canUnwatchedpages = $this->getPermissionManager()->userHasRight( $user, 'unwatchedpages' );
960  $unwatchedPageThreshold = $this->getConfig()->get( 'UnwatchedPageThreshold' );
961  if ( !$canUnwatchedpages && !is_int( $unwatchedPageThreshold ) ) {
962  return;
963  }
964 
965  $this->showZeroWatchers = $canUnwatchedpages;
966 
967  $countOptions = [];
968  if ( !$canUnwatchedpages ) {
969  $countOptions['minimumWatchers'] = $unwatchedPageThreshold;
970  }
971 
972  $this->watchers = $this->watchedItemStore->countWatchersMultiple(
973  $this->everything,
974  $countOptions
975  );
976  }
977 
984  private function getVisitingWatcherInfo() {
985  $config = $this->getConfig();
986  $user = $this->getUser();
987  $db = $this->getDB();
988 
989  $canUnwatchedpages = $this->getPermissionManager()->userHasRight( $user, 'unwatchedpages' );
990  $unwatchedPageThreshold = $this->getConfig()->get( 'UnwatchedPageThreshold' );
991  if ( !$canUnwatchedpages && !is_int( $unwatchedPageThreshold ) ) {
992  return;
993  }
994 
995  $this->showZeroWatchers = $canUnwatchedpages;
996 
997  $titlesWithThresholds = [];
998  if ( $this->titles ) {
999  $lb = $this->linkBatchFactory->newLinkBatch( $this->titles );
1000 
1001  // Fetch last edit timestamps for pages
1002  $this->resetQueryParams();
1003  $this->addTables( [ 'page', 'revision' ] );
1004  $this->addFields( [ 'page_namespace', 'page_title', 'rev_timestamp' ] );
1005  $this->addWhere( [
1006  'page_latest = rev_id',
1007  $lb->constructSet( 'page', $db ),
1008  ] );
1009  $this->addOption( 'GROUP BY', [ 'page_namespace', 'page_title' ] );
1010  $timestampRes = $this->select( __METHOD__ );
1011 
1012  $age = $config->get( 'WatchersMaxAge' );
1013  $timestamps = [];
1014  foreach ( $timestampRes as $row ) {
1015  $revTimestamp = wfTimestamp( TS_UNIX, (int)$row->rev_timestamp );
1016  $timestamps[$row->page_namespace][$row->page_title] = (int)$revTimestamp - $age;
1017  }
1018  $titlesWithThresholds = array_map(
1019  function ( LinkTarget $target ) use ( $timestamps ) {
1020  return [
1021  $target, $timestamps[$target->getNamespace()][$target->getDBkey()]
1022  ];
1023  },
1025  );
1026  }
1027 
1028  if ( $this->missing ) {
1029  $titlesWithThresholds = array_merge(
1030  $titlesWithThresholds,
1031  array_map(
1032  function ( LinkTarget $target ) {
1033  return [ $target, null ];
1034  },
1036  )
1037  );
1038  }
1039  $this->visitingwatchers = $this->watchedItemStore->countVisitingWatchersMultiple(
1040  $titlesWithThresholds,
1041  !$canUnwatchedpages ? $unwatchedPageThreshold : null
1042  );
1043  }
1044 
1045  public function getCacheMode( $params ) {
1046  // Other props depend on something about the current user
1047  $publicProps = [
1048  'protection',
1049  'talkid',
1050  'subjectid',
1051  'url',
1052  'preload',
1053  'displaytitle',
1054  'varianttitles',
1055  ];
1056  if ( array_diff( (array)$params['prop'], $publicProps ) ) {
1057  return 'private';
1058  }
1059 
1060  // testactions also depends on the current user
1061  if ( $params['testactions'] ) {
1062  return 'private';
1063  }
1064 
1065  if ( $params['token'] !== null ) {
1066  return 'private';
1067  }
1068 
1069  return 'public';
1070  }
1071 
1072  public function getAllowedParams() {
1073  return [
1074  'prop' => [
1075  ApiBase::PARAM_ISMULTI => true,
1076  ApiBase::PARAM_TYPE => [
1077  'protection',
1078  'talkid',
1079  'watched', # private
1080  'watchers', # private
1081  'visitingwatchers', # private
1082  'notificationtimestamp', # private
1083  'subjectid',
1084  'url',
1085  'readable', # private
1086  'preload',
1087  'displaytitle',
1088  'varianttitles',
1089  'linkclasses', # private: stub length (and possibly hook colors)
1090  // If you add more properties here, please consider whether they
1091  // need to be added to getCacheMode()
1092  ],
1095  'readable' => true, // Since 1.32
1096  ],
1097  ],
1098  'linkcontext' => [
1099  ApiBase::PARAM_TYPE => 'title',
1100  ApiBase::PARAM_DFLT => $this->titleFactory->newMainPage()->getPrefixedText(),
1101  TitleDef::PARAM_RETURN_OBJECT => true,
1102  ],
1103  'testactions' => [
1104  ApiBase::PARAM_TYPE => 'string',
1105  ApiBase::PARAM_ISMULTI => true,
1106  ],
1107  'testactionsdetail' => [
1108  ApiBase::PARAM_TYPE => [ 'boolean', 'full', 'quick' ],
1109  ApiBase::PARAM_DFLT => 'boolean',
1111  ],
1112  'token' => [
1113  ApiBase::PARAM_DEPRECATED => true,
1114  ApiBase::PARAM_ISMULTI => true,
1115  ApiBase::PARAM_TYPE => array_keys( $this->getTokenFunctions() )
1116  ],
1117  'continue' => [
1118  ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
1119  ],
1120  ];
1121  }
1122 
1123  protected function getExamplesMessages() {
1124  return [
1125  'action=query&prop=info&titles=Main%20Page'
1126  => 'apihelp-query+info-example-simple',
1127  'action=query&prop=info&inprop=protection&titles=Main%20Page'
1128  => 'apihelp-query+info-example-protection',
1129  ];
1130  }
1131 
1132  public function getHelpUrls() {
1133  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Info';
1134  }
1135 }
ApiQueryInfo\$talkids
$talkids
Definition: ApiQueryInfo.php:72
ApiQueryInfo\extractPageInfo
extractPageInfo( $pageid, $title)
Get a result array with information about a title.
Definition: ApiQueryInfo.php:446
ApiQueryInfo\$fld_linkclasses
bool $fld_linkclasses
Whether to include link class information for the given page titles.
Definition: ApiQueryInfo.php:57
ApiQueryInfo\getMoveToken
static getMoveToken(User $user)
Definition: ApiQueryInfo.php:240
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:70
ApiQueryInfo\$everything
Title[] $everything
Definition: ApiQueryInfo.php:66
ApiQueryBase\addFields
addFields( $value)
Add a set of fields to select to the internal array.
Definition: ApiQueryBase.php:212
ApiQuery
This is the main query class.
Definition: ApiQuery.php:37
ApiQueryInfo\getEditToken
static getEditToken(User $user)
Definition: ApiQueryInfo.php:213
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1289
ApiQueryInfo\getImportToken
static getImportToken(User $user)
Definition: ApiQueryInfo.php:286
ApiQueryInfo\$fld_url
$fld_url
Definition: ApiQueryInfo.php:47
ApiQueryInfo\$subjectids
$subjectids
Definition: ApiQueryInfo.php:72
ApiQueryInfo\$displaytitles
$displaytitles
Definition: ApiQueryInfo.php:72
ApiQueryBase\resetQueryParams
resetQueryParams()
Blank the internal arrays with query parameters.
Definition: ApiQueryBase.php:156
User\isRegistered
isRegistered()
Get whether the user is registered.
Definition: User.php:2973
ApiQueryInfo\getProtectionInfo
getProtectionInfo()
Get information about protections and put it in $protections.
Definition: ApiQueryInfo.php:629
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:166
ApiQueryInfo\$pageTouched
$pageTouched
Definition: ApiQueryInfo.php:68
ApiQueryInfo\$showZeroWatchers
$showZeroWatchers
Definition: ApiQueryInfo.php:86
ApiQueryInfo\getProtectToken
static getProtectToken(User $user)
Definition: ApiQueryInfo.php:231
ApiQueryInfo\__construct
__construct(ApiQuery $queryModule, $moduleName, Language $contentLanguage, LinkBatchFactory $linkBatchFactory, NamespaceInfo $namespaceInfo, TitleFactory $titleFactory, WatchedItemStore $watchedItemStore)
Definition: ApiQueryInfo.php:101
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:102
ApiQueryInfo\resetTokenCache
static resetTokenCache()
Definition: ApiQueryInfo.php:179
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1831
ApiQueryInfo\$tokenFunctions
$tokenFunctions
Definition: ApiQueryInfo.php:88
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:69
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:558
ApiQueryInfo\getVisitingWatcherInfo
getVisitingWatcherInfo()
Get the count of watchers who have visited recent edits and put it in $this->visitingwatchers.
Definition: ApiQueryInfo.php:984
ApiQueryBase\addOption
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
Definition: ApiQueryBase.php:378
$res
$res
Definition: testCompression.php:57
ContextSource\getUser
getUser()
Stable to override.
Definition: ContextSource.php:134
ApiQueryInfo
A query module to show basic page information.
Definition: ApiQueryInfo.php:33
ApiBase\PARAM_DEPRECATED_VALUES
const PARAM_DEPRECATED_VALUES
Definition: ApiBase.php:81
ApiBase\lacksSameOriginSecurity
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:486
ApiQueryInfo\$linkClasses
array< int, string[]> $linkClasses
Mapping of page id to list of 'extra link classes' for the given page.
Definition: ApiQueryInfo.php:84
NS_MAIN
const NS_MAIN
Definition: Defines.php:63
ApiQueryInfo\$countTestedActions
$countTestedActions
Definition: ApiQueryInfo.php:90
ApiQueryInfo\getAllVariants
getAllVariants( $text, $ns=NS_MAIN)
Definition: ApiQueryInfo.php:897
ApiQueryInfo\$fld_varianttitles
$fld_varianttitles
Definition: ApiQueryInfo.php:51
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
Definition: ApiBase.php:74
MediaWiki\Linker\LinkTarget\getNamespace
getNamespace()
Get the namespace index.
ApiQueryInfo\$visitingwatchers
$visitingwatchers
Definition: ApiQueryInfo.php:71
Language\autoConvert
autoConvert( $text, $variant=false)
convert text to a variant
Definition: Language.php:4228
ApiQueryInfo\getUnblockToken
static getUnblockToken(User $user)
Definition: ApiQueryInfo.php:258
ApiQueryBase
This is a base class for all Query modules.
Definition: ApiQueryBase.php:37
MediaWiki\Cache\LinkBatchFactory
Definition: LinkBatchFactory.php:38
ApiQueryInfo\$pageRestrictions
$pageRestrictions
Definition: ApiQueryInfo.php:68
ApiQueryBase\getDB
getDB()
Get the Query database connection (read-only) Stable to override.
Definition: ApiQueryBase.php:117
ApiQueryInfo\getLinkClasses
getLinkClasses(?LinkTarget $context_title=null)
Fetch the set of extra link classes associated with links to the set of titles ("link colours"),...
Definition: ApiQueryInfo.php:847
User\isBlockedFromEmailuser
isBlockedFromEmailuser()
Get whether the user is blocked from using Special:Emailuser.
Definition: User.php:3687
ApiQueryBase\addTables
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
Definition: ApiQueryBase.php:182
ApiQueryBase\select
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
Definition: ApiQueryBase.php:399
ApiQueryInfo\$titles
Title[] $titles
Definition: ApiQueryInfo.php:62
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:706
ApiQueryInfo\$fld_talkid
$fld_talkid
Definition: ApiQueryInfo.php:46
$title
$title
Definition: testCompression.php:38
PROTO_CANONICAL
const PROTO_CANONICAL
Definition: Defines.php:206
ApiQueryInfo\$fld_displaytitle
$fld_displaytitle
Definition: ApiQueryInfo.php:51
ApiQueryInfo\$contentLanguage
Language $contentLanguage
Definition: ApiQueryInfo.php:36
ApiQueryInfo\$notificationtimestamps
$notificationtimestamps
Definition: ApiQueryInfo.php:72
ApiQueryInfo\getDeleteToken
static getDeleteToken(User $user)
Definition: ApiQueryInfo.php:222
ApiQueryInfo\getTSIDs
getTSIDs()
Get talk page IDs (if requested) and subject page IDs (if requested) and put them in $talkids and $su...
Definition: ApiQueryInfo.php:780
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:205
ApiQueryInfo\getWatchedInfo
getWatchedInfo()
Get information about watched status and put it in $this->watched and $this->notificationtimestamps.
Definition: ApiQueryInfo.php:915
ApiQueryInfo\$watched
$watched
Definition: ApiQueryInfo.php:71
ApiQueryInfo\$params
$params
Definition: ApiQueryInfo.php:59
ApiQueryInfo\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiQueryInfo.php:1132
MediaWiki\Permissions\PermissionManager
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Definition: PermissionManager.php:51
ApiResult\setIndexedTagName
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:601
ApiQueryInfo\$pageIsNew
$pageIsNew
Definition: ApiQueryInfo.php:68
ApiQueryInfo\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiQueryInfo.php:1123
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1550
ApiQueryInfo\getTokenFunctions
getTokenFunctions()
Get an array mapping token names to their handler functions.
Definition: ApiQueryInfo.php:146
ApiBase\LIMIT_SML2
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition: ApiBase.php:166
ApiQueryInfo\$fld_preload
$fld_preload
Definition: ApiQueryInfo.php:51
ApiQueryInfo\getEmailToken
static getEmailToken(User $user)
Definition: ApiQueryInfo.php:268
ApiBase\getPermissionManager
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition: ApiBase.php:627
MediaWiki\Linker\LinkTarget\getDBkey
getDBkey()
Get the main part with underscores.
ApiQueryInfo\$linkBatchFactory
LinkBatchFactory $linkBatchFactory
Definition: ApiQueryInfo.php:38
ApiQueryInfo\getWatchToken
static getWatchToken(User $user)
Definition: ApiQueryInfo.php:306
ApiQueryBase\addWhereFld
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
Definition: ApiQueryBase.php:282
ApiQueryBase\getPageSet
getPageSet()
Get the PageSet object to work on Stable to override.
Definition: ApiQueryBase.php:143
ApiQueryInfo\$fld_watchers
$fld_watchers
Definition: ApiQueryInfo.php:49
ApiQueryInfo\getOptionsToken
static getOptionsToken(User $user)
Definition: ApiQueryInfo.php:324
ApiQueryInfo\getCacheMode
getCacheMode( $params)
Get the cache mode for the data generated by this module.
Definition: ApiQueryInfo.php:1045
WatchedItemStore
Storage layer class for WatchedItems.
Definition: WatchedItemStore.php:28
ApiQueryInfo\$fld_subjectid
$fld_subjectid
Definition: ApiQueryInfo.php:47
Title
Represents a title within MediaWiki.
Definition: Title.php:46
Wikimedia\ParamValidator\ParamValidator::TypeDef\TitleDef
Type definition for page titles.
Definition: TitleDef.php:22
ApiQueryInfo\$watchlistExpiries
array< int, array< string, string > > $watchlistExpiries
Watchlist expiries that corresponds with the $watched property.
Definition: ApiQueryInfo.php:78
ApiQueryInfo\$fld_watched
$fld_watched
Definition: ApiQueryInfo.php:48
ApiQueryInfo\getDisplayTitle
getDisplayTitle()
Definition: ApiQueryInfo.php:819
ApiQueryInfo\$fld_protection
$fld_protection
Definition: ApiQueryInfo.php:46
ApiQueryInfo\$watchedItemStore
WatchedItemStore $watchedItemStore
Definition: ApiQueryInfo.php:44
ApiQueryInfo\$watchers
$watchers
Definition: ApiQueryInfo.php:71
ApiQueryInfo\getUserToken
static getUserToken(User $user, string $right)
Temporary method until the token methods are removed entirely.
Definition: ApiQueryInfo.php:192
ApiQueryInfo\$pageLatest
$pageLatest
Definition: ApiQueryInfo.php:69
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:67
ApiQueryInfo\$restrictionTypes
$restrictionTypes
Definition: ApiQueryInfo.php:71
TitleFactory
Creates Title objects.
Definition: TitleFactory.php:33
ApiQueryInfo\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiQueryInfo.php:1072
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:68
ApiQueryInfo\$protections
$protections
Definition: ApiQueryInfo.php:71
ApiQueryInfo\getBlockToken
static getBlockToken(User $user)
Definition: ApiQueryInfo.php:249
$source
$source
Definition: mwdoc-filter.php:34
ApiResult\formatExpiry
static formatExpiry( $expiry, $infinity='infinity')
Format an expiry timestamp for API output.
Definition: ApiResult.php:1189
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:453
ApiQueryInfo\$fld_notificationtimestamp
$fld_notificationtimestamp
Definition: ApiQueryInfo.php:50
ApiQueryBase\addWhere
addWhere( $value)
Add a set of WHERE clauses to the internal array.
Definition: ApiQueryBase.php:245
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:35
Title\compare
static compare(LinkTarget $a, LinkTarget $b)
Callback for usort() to do title sorts by (namespace, title)
Definition: Title.php:881
$t
$t
Definition: testCompression.php:74
ApiQueryBase\setContinueEnumParameter
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
Definition: ApiQueryBase.php:515
ApiQueryInfo\$pageIsRedir
$pageIsRedir
Definition: ApiQueryInfo.php:68
ApiQueryInfo\$titleFactory
TitleFactory $titleFactory
Definition: ApiQueryInfo.php:42
NS_FILE
const NS_FILE
Definition: Defines.php:69
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
ApiQueryInfo\$cachedTokens
static string[] $cachedTokens
Definition: ApiQueryInfo.php:174
ApiBase\PARAM_HELP_MSG_PER_VALUE
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:135
ApiQueryInfo\getVariantTitles
getVariantTitles()
Definition: ApiQueryInfo.php:885
User\getEditToken
getEditToken( $salt='', $request=null)
Initialize (if necessary) and return a session token value which can be used in edit forms to show th...
Definition: User.php:3774
ApiBase\getHookRunner
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:652
ApiQueryInfo\$fld_readable
$fld_readable
Definition: ApiQueryInfo.php:48
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:56
ApiQueryInfo\requestExtraData
requestExtraData( $pageSet)
Definition: ApiQueryInfo.php:122
ApiQueryInfo\$fld_visitingwatchers
$fld_visitingwatchers
Definition: ApiQueryInfo.php:49
ApiQueryInfo\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiQueryInfo.php:337
ApiQueryInfo\$namespaceInfo
NamespaceInfo $namespaceInfo
Definition: ApiQueryInfo.php:40
ApiQueryInfo\getWatcherInfo
getWatcherInfo()
Get the count of watchers and put it in $this->watchers.
Definition: ApiQueryInfo.php:953
ApiBase\errorArrayToStatus
errorArrayToStatus(array $errors, User $user=null)
Turn an array of message keys or key+param arrays into a Status.
Definition: ApiBase.php:1182
ApiQueryInfo\$pageLength
$pageLength
Definition: ApiQueryInfo.php:69
ApiBase\getErrorFormatter
getErrorFormatter()
Stable to override.
Definition: ApiBase.php:572
ApiQueryInfo\$missing
Title[] $missing
Definition: ApiQueryInfo.php:64
User\canSendEmail
canSendEmail()
Is this user allowed to send e-mails within limits of current site configuration?
Definition: User.php:3998
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:42
ApiQueryInfo\$variantTitles
$variantTitles
Definition: ApiQueryInfo.php:72
ApiBase\LIMIT_SML1
const LIMIT_SML1
Slow query, standard limit.
Definition: ApiBase.php:164
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:494