MediaWiki  1.29.1
ApiPageSet.php
Go to the documentation of this file.
1 <?php
29 
44 class ApiPageSet extends ApiBase {
49  const DISABLE_GENERATORS = 1;
50 
51  private $mDbSource;
52  private $mParams;
54  private $mConvertTitles;
56 
57  private $mAllPages = []; // [ns][dbkey] => page_id or negative when missing
58  private $mTitles = [];
59  private $mGoodAndMissingPages = []; // [ns][dbkey] => page_id or negative when missing
60  private $mGoodPages = []; // [ns][dbkey] => page_id
61  private $mGoodTitles = [];
62  private $mMissingPages = []; // [ns][dbkey] => fake page_id
63  private $mMissingTitles = [];
65  private $mInvalidTitles = [];
66  private $mMissingPageIDs = [];
67  private $mRedirectTitles = [];
68  private $mSpecialTitles = [];
69  private $mAllSpecials = []; // separate from mAllPages to avoid breaking getAllTitlesByNamespace()
70  private $mNormalizedTitles = [];
71  private $mInterwikiTitles = [];
73  private $mPendingRedirectIDs = [];
74  private $mPendingRedirectSpecialPages = []; // [dbkey] => [ Title $from, Title $to ]
76  private $mConvertedTitles = [];
77  private $mGoodRevIDs = [];
78  private $mLiveRevIDs = [];
79  private $mDeletedRevIDs = [];
80  private $mMissingRevIDs = [];
81  private $mGeneratorData = []; // [ns][dbkey] => data array
82  private $mFakePageId = -1;
83  private $mCacheMode = 'public';
84  private $mRequestedPageFields = [];
89 
97  private static function addValues( array &$result, $values, $flags = [], $name = null ) {
98  foreach ( $values as $val ) {
99  if ( $val instanceof Title ) {
100  $v = [];
101  ApiQueryBase::addTitleInfo( $v, $val );
102  } elseif ( $name !== null ) {
103  $v = [ $name => $val ];
104  } else {
105  $v = $val;
106  }
107  foreach ( $flags as $flag ) {
108  $v[$flag] = true;
109  }
110  $result[] = $v;
111  }
112  }
113 
121  public function __construct( ApiBase $dbSource, $flags = 0, $defaultNamespace = NS_MAIN ) {
122  parent::__construct( $dbSource->getMain(), $dbSource->getModuleName() );
123  $this->mDbSource = $dbSource;
124  $this->mAllowGenerator = ( $flags & ApiPageSet::DISABLE_GENERATORS ) == 0;
125  $this->mDefaultNamespace = $defaultNamespace;
126 
127  $this->mParams = $this->extractRequestParams();
128  $this->mResolveRedirects = $this->mParams['redirects'];
129  $this->mConvertTitles = $this->mParams['converttitles'];
130  }
131 
136  public function executeDryRun() {
137  $this->executeInternal( true );
138  }
139 
143  public function execute() {
144  $this->executeInternal( false );
145  }
146 
152  private function executeInternal( $isDryRun ) {
153  $generatorName = $this->mAllowGenerator ? $this->mParams['generator'] : null;
154  if ( isset( $generatorName ) ) {
155  $dbSource = $this->mDbSource;
156  if ( !$dbSource instanceof ApiQuery ) {
157  // If the parent container of this pageset is not ApiQuery, we must create it to run generator
158  $dbSource = $this->getMain()->getModuleManager()->getModule( 'query' );
159  }
160  $generator = $dbSource->getModuleManager()->getModule( $generatorName, null, true );
161  if ( $generator === null ) {
162  $this->dieWithError( [ 'apierror-badgenerator-unknown', $generatorName ], 'badgenerator' );
163  }
164  if ( !$generator instanceof ApiQueryGeneratorBase ) {
165  $this->dieWithError( [ 'apierror-badgenerator-notgenerator', $generatorName ], 'badgenerator' );
166  }
167  // Create a temporary pageset to store generator's output,
168  // add any additional fields generator may need, and execute pageset to populate titles/pageids
169  $tmpPageSet = new ApiPageSet( $dbSource, ApiPageSet::DISABLE_GENERATORS );
170  $generator->setGeneratorMode( $tmpPageSet );
171  $this->mCacheMode = $generator->getCacheMode( $generator->extractRequestParams() );
172 
173  if ( !$isDryRun ) {
174  $generator->requestExtraData( $tmpPageSet );
175  }
176  $tmpPageSet->executeInternal( $isDryRun );
177 
178  // populate this pageset with the generator output
179  if ( !$isDryRun ) {
180  $generator->executeGenerator( $this );
181 
182  // Avoid PHP 7.1 warning of passing $this by reference
183  $apiModule = $this;
184  Hooks::run( 'APIQueryGeneratorAfterExecute', [ &$generator, &$apiModule ] );
185  } else {
186  // Prevent warnings from being reported on these parameters
187  $main = $this->getMain();
188  foreach ( $generator->extractRequestParams() as $paramName => $param ) {
189  $main->markParamsUsed( $generator->encodeParamName( $paramName ) );
190  }
191  }
192 
193  if ( !$isDryRun ) {
194  $this->resolvePendingRedirects();
195  }
196  } else {
197  // Only one of the titles/pageids/revids is allowed at the same time
198  $dataSource = null;
199  if ( isset( $this->mParams['titles'] ) ) {
200  $dataSource = 'titles';
201  }
202  if ( isset( $this->mParams['pageids'] ) ) {
203  if ( isset( $dataSource ) ) {
204  $this->dieWithError(
205  [
206  'apierror-invalidparammix-cannotusewith',
207  $this->encodeParamName( 'pageids' ),
208  $this->encodeParamName( $dataSource )
209  ],
210  'multisource'
211  );
212  }
213  $dataSource = 'pageids';
214  }
215  if ( isset( $this->mParams['revids'] ) ) {
216  if ( isset( $dataSource ) ) {
217  $this->dieWithError(
218  [
219  'apierror-invalidparammix-cannotusewith',
220  $this->encodeParamName( 'revids' ),
221  $this->encodeParamName( $dataSource )
222  ],
223  'multisource'
224  );
225  }
226  $dataSource = 'revids';
227  }
228 
229  if ( !$isDryRun ) {
230  // Populate page information with the original user input
231  switch ( $dataSource ) {
232  case 'titles':
233  $this->initFromTitles( $this->mParams['titles'] );
234  break;
235  case 'pageids':
236  $this->initFromPageIds( $this->mParams['pageids'] );
237  break;
238  case 'revids':
239  if ( $this->mResolveRedirects ) {
240  $this->addWarning( 'apiwarn-redirectsandrevids' );
241  }
242  $this->mResolveRedirects = false;
243  $this->initFromRevIDs( $this->mParams['revids'] );
244  break;
245  default:
246  // Do nothing - some queries do not need any of the data sources.
247  break;
248  }
249  }
250  }
251  }
252 
257  public function isResolvingRedirects() {
259  }
260 
269  public function getDataSource() {
270  if ( $this->mAllowGenerator && isset( $this->mParams['generator'] ) ) {
271  return 'generator';
272  }
273  if ( isset( $this->mParams['titles'] ) ) {
274  return 'titles';
275  }
276  if ( isset( $this->mParams['pageids'] ) ) {
277  return 'pageids';
278  }
279  if ( isset( $this->mParams['revids'] ) ) {
280  return 'revids';
281  }
282 
283  return null;
284  }
285 
291  public function requestField( $fieldName ) {
292  $this->mRequestedPageFields[$fieldName] = null;
293  }
294 
301  public function getCustomField( $fieldName ) {
302  return $this->mRequestedPageFields[$fieldName];
303  }
304 
311  public function getPageTableFields() {
312  // Ensure we get minimum required fields
313  // DON'T change this order
314  $pageFlds = [
315  'page_namespace' => null,
316  'page_title' => null,
317  'page_id' => null,
318  ];
319 
320  if ( $this->mResolveRedirects ) {
321  $pageFlds['page_is_redirect'] = null;
322  }
323 
324  if ( $this->getConfig()->get( 'ContentHandlerUseDB' ) ) {
325  $pageFlds['page_content_model'] = null;
326  }
327 
328  if ( $this->getConfig()->get( 'PageLanguageUseDB' ) ) {
329  $pageFlds['page_lang'] = null;
330  }
331 
332  foreach ( LinkCache::getSelectFields() as $field ) {
333  $pageFlds[$field] = null;
334  }
335 
336  $pageFlds = array_merge( $pageFlds, $this->mRequestedPageFields );
337 
338  return array_keys( $pageFlds );
339  }
340 
347  public function getAllTitlesByNamespace() {
348  return $this->mAllPages;
349  }
350 
355  public function getTitles() {
356  return $this->mTitles;
357  }
358 
363  public function getTitleCount() {
364  return count( $this->mTitles );
365  }
366 
371  public function getGoodTitlesByNamespace() {
372  return $this->mGoodPages;
373  }
374 
379  public function getGoodTitles() {
380  return $this->mGoodTitles;
381  }
382 
387  public function getGoodTitleCount() {
388  return count( $this->mGoodTitles );
389  }
390 
396  public function getMissingTitlesByNamespace() {
397  return $this->mMissingPages;
398  }
399 
405  public function getMissingTitles() {
406  return $this->mMissingTitles;
407  }
408 
415  }
416 
421  public function getGoodAndMissingTitles() {
422  return $this->mGoodTitles + $this->mMissingTitles;
423  }
424 
431  public function getInvalidTitles() {
432  wfDeprecated( __METHOD__, '1.26' );
433  return array_map( function ( $t ) {
434  return $t['title'];
436  }
437 
443  public function getInvalidTitlesAndReasons() {
444  return $this->mInvalidTitles;
445  }
446 
451  public function getMissingPageIDs() {
452  return $this->mMissingPageIDs;
453  }
454 
460  public function getRedirectTitles() {
461  return $this->mRedirectTitles;
462  }
463 
471  public function getRedirectTitlesAsResult( $result = null ) {
472  $values = [];
473  foreach ( $this->getRedirectTitles() as $titleStrFrom => $titleTo ) {
474  $r = [
475  'from' => strval( $titleStrFrom ),
476  'to' => $titleTo->getPrefixedText(),
477  ];
478  if ( $titleTo->hasFragment() ) {
479  $r['tofragment'] = $titleTo->getFragment();
480  }
481  if ( $titleTo->isExternal() ) {
482  $r['tointerwiki'] = $titleTo->getInterwiki();
483  }
484  if ( isset( $this->mResolvedRedirectTitles[$titleStrFrom] ) ) {
485  $titleFrom = $this->mResolvedRedirectTitles[$titleStrFrom];
486  $ns = $titleFrom->getNamespace();
487  $dbkey = $titleFrom->getDBkey();
488  if ( isset( $this->mGeneratorData[$ns][$dbkey] ) ) {
489  $r = array_merge( $this->mGeneratorData[$ns][$dbkey], $r );
490  }
491  }
492 
493  $values[] = $r;
494  }
495  if ( !empty( $values ) && $result ) {
496  ApiResult::setIndexedTagName( $values, 'r' );
497  }
498 
499  return $values;
500  }
501 
507  public function getNormalizedTitles() {
509  }
510 
518  public function getNormalizedTitlesAsResult( $result = null ) {
520 
521  $values = [];
522  foreach ( $this->getNormalizedTitles() as $rawTitleStr => $titleStr ) {
523  $encode = ( $wgContLang->normalize( $rawTitleStr ) !== $rawTitleStr );
524  $values[] = [
525  'fromencoded' => $encode,
526  'from' => $encode ? rawurlencode( $rawTitleStr ) : $rawTitleStr,
527  'to' => $titleStr
528  ];
529  }
530  if ( !empty( $values ) && $result ) {
531  ApiResult::setIndexedTagName( $values, 'n' );
532  }
533 
534  return $values;
535  }
536 
542  public function getConvertedTitles() {
544  }
545 
553  public function getConvertedTitlesAsResult( $result = null ) {
554  $values = [];
555  foreach ( $this->getConvertedTitles() as $rawTitleStr => $titleStr ) {
556  $values[] = [
557  'from' => $rawTitleStr,
558  'to' => $titleStr
559  ];
560  }
561  if ( !empty( $values ) && $result ) {
562  ApiResult::setIndexedTagName( $values, 'c' );
563  }
564 
565  return $values;
566  }
567 
573  public function getInterwikiTitles() {
575  }
576 
585  public function getInterwikiTitlesAsResult( $result = null, $iwUrl = false ) {
586  $values = [];
587  foreach ( $this->getInterwikiTitles() as $rawTitleStr => $interwikiStr ) {
588  $item = [
589  'title' => $rawTitleStr,
590  'iw' => $interwikiStr,
591  ];
592  if ( $iwUrl ) {
593  $title = Title::newFromText( $rawTitleStr );
594  $item['url'] = $title->getFullURL( '', false, PROTO_CURRENT );
595  }
596  $values[] = $item;
597  }
598  if ( !empty( $values ) && $result ) {
599  ApiResult::setIndexedTagName( $values, 'i' );
600  }
601 
602  return $values;
603  }
604 
619  public function getInvalidTitlesAndRevisions( $invalidChecks = [ 'invalidTitles',
620  'special', 'missingIds', 'missingRevIds', 'missingTitles', 'interwikiTitles' ]
621  ) {
622  $result = [];
623  if ( in_array( 'invalidTitles', $invalidChecks ) ) {
624  self::addValues( $result, $this->getInvalidTitlesAndReasons(), [ 'invalid' ] );
625  }
626  if ( in_array( 'special', $invalidChecks ) ) {
627  $known = [];
628  $unknown = [];
629  foreach ( $this->getSpecialTitles() as $title ) {
630  if ( $title->isKnown() ) {
631  $known[] = $title;
632  } else {
633  $unknown[] = $title;
634  }
635  }
636  self::addValues( $result, $unknown, [ 'special', 'missing' ] );
637  self::addValues( $result, $known, [ 'special' ] );
638  }
639  if ( in_array( 'missingIds', $invalidChecks ) ) {
640  self::addValues( $result, $this->getMissingPageIDs(), [ 'missing' ], 'pageid' );
641  }
642  if ( in_array( 'missingRevIds', $invalidChecks ) ) {
643  self::addValues( $result, $this->getMissingRevisionIDs(), [ 'missing' ], 'revid' );
644  }
645  if ( in_array( 'missingTitles', $invalidChecks ) ) {
646  $known = [];
647  $unknown = [];
648  foreach ( $this->getMissingTitles() as $title ) {
649  if ( $title->isKnown() ) {
650  $known[] = $title;
651  } else {
652  $unknown[] = $title;
653  }
654  }
655  self::addValues( $result, $unknown, [ 'missing' ] );
656  self::addValues( $result, $known, [ 'missing', 'known' ] );
657  }
658  if ( in_array( 'interwikiTitles', $invalidChecks ) ) {
660  }
661 
662  return $result;
663  }
664 
669  public function getRevisionIDs() {
670  return $this->mGoodRevIDs;
671  }
672 
677  public function getLiveRevisionIDs() {
678  return $this->mLiveRevIDs;
679  }
680 
685  public function getDeletedRevisionIDs() {
686  return $this->mDeletedRevIDs;
687  }
688 
693  public function getMissingRevisionIDs() {
694  return $this->mMissingRevIDs;
695  }
696 
703  public function getMissingRevisionIDsAsResult( $result = null ) {
704  $values = [];
705  foreach ( $this->getMissingRevisionIDs() as $revid ) {
706  $values[$revid] = [
707  'revid' => $revid
708  ];
709  }
710  if ( !empty( $values ) && $result ) {
711  ApiResult::setIndexedTagName( $values, 'rev' );
712  }
713 
714  return $values;
715  }
716 
721  public function getSpecialTitles() {
722  return $this->mSpecialTitles;
723  }
724 
729  public function getRevisionCount() {
730  return count( $this->getRevisionIDs() );
731  }
732 
737  public function populateFromTitles( $titles ) {
738  $this->initFromTitles( $titles );
739  }
740 
745  public function populateFromPageIDs( $pageIDs ) {
746  $this->initFromPageIds( $pageIDs );
747  }
748 
758  public function populateFromQueryResult( $db, $queryResult ) {
759  $this->initFromQueryResult( $queryResult );
760  }
761 
766  public function populateFromRevisionIDs( $revIDs ) {
767  $this->initFromRevIDs( $revIDs );
768  }
769 
774  public function processDbRow( $row ) {
775  // Store Title object in various data structures
776  $title = Title::newFromRow( $row );
777 
778  LinkCache::singleton()->addGoodLinkObjFromRow( $title, $row );
779 
780  $pageId = intval( $row->page_id );
781  $this->mAllPages[$row->page_namespace][$row->page_title] = $pageId;
782  $this->mTitles[] = $title;
783 
784  if ( $this->mResolveRedirects && $row->page_is_redirect == '1' ) {
785  $this->mPendingRedirectIDs[$pageId] = $title;
786  } else {
787  $this->mGoodPages[$row->page_namespace][$row->page_title] = $pageId;
788  $this->mGoodAndMissingPages[$row->page_namespace][$row->page_title] = $pageId;
789  $this->mGoodTitles[$pageId] = $title;
790  }
791 
792  foreach ( $this->mRequestedPageFields as $fieldName => &$fieldValues ) {
793  $fieldValues[$pageId] = $row->$fieldName;
794  }
795  }
796 
813  private function initFromTitles( $titles ) {
814  // Get validated and normalized title objects
815  $linkBatch = $this->processTitlesArray( $titles );
816  if ( $linkBatch->isEmpty() ) {
817  // There might be special-page redirects
818  $this->resolvePendingRedirects();
819  return;
820  }
821 
822  $db = $this->getDB();
823  $set = $linkBatch->constructSet( 'page', $db );
824 
825  // Get pageIDs data from the `page` table
826  $res = $db->select( 'page', $this->getPageTableFields(), $set,
827  __METHOD__ );
828 
829  // Hack: get the ns:titles stored in [ ns => [ titles ] ] format
830  $this->initFromQueryResult( $res, $linkBatch->data, true ); // process Titles
831 
832  // Resolve any found redirects
833  $this->resolvePendingRedirects();
834  }
835 
840  private function initFromPageIds( $pageids ) {
841  if ( !$pageids ) {
842  return;
843  }
844 
845  $pageids = array_map( 'intval', $pageids ); // paranoia
846  $remaining = array_flip( $pageids );
847 
848  $pageids = self::getPositiveIntegers( $pageids );
849 
850  $res = null;
851  if ( !empty( $pageids ) ) {
852  $set = [
853  'page_id' => $pageids
854  ];
855  $db = $this->getDB();
856 
857  // Get pageIDs data from the `page` table
858  $res = $db->select( 'page', $this->getPageTableFields(), $set,
859  __METHOD__ );
860  }
861 
862  $this->initFromQueryResult( $res, $remaining, false ); // process PageIDs
863 
864  // Resolve any found redirects
865  $this->resolvePendingRedirects();
866  }
867 
878  private function initFromQueryResult( $res, &$remaining = null, $processTitles = null ) {
879  if ( !is_null( $remaining ) && is_null( $processTitles ) ) {
880  ApiBase::dieDebug( __METHOD__, 'Missing $processTitles parameter when $remaining is provided' );
881  }
882 
883  $usernames = [];
884  if ( $res ) {
885  foreach ( $res as $row ) {
886  $pageId = intval( $row->page_id );
887 
888  // Remove found page from the list of remaining items
889  if ( isset( $remaining ) ) {
890  if ( $processTitles ) {
891  unset( $remaining[$row->page_namespace][$row->page_title] );
892  } else {
893  unset( $remaining[$pageId] );
894  }
895  }
896 
897  // Store any extra fields requested by modules
898  $this->processDbRow( $row );
899 
900  // Need gender information
901  if ( MWNamespace::hasGenderDistinction( $row->page_namespace ) ) {
902  $usernames[] = $row->page_title;
903  }
904  }
905  }
906 
907  if ( isset( $remaining ) ) {
908  // Any items left in the $remaining list are added as missing
909  if ( $processTitles ) {
910  // The remaining titles in $remaining are non-existent pages
911  $linkCache = LinkCache::singleton();
912  foreach ( $remaining as $ns => $dbkeys ) {
913  foreach ( array_keys( $dbkeys ) as $dbkey ) {
914  $title = Title::makeTitle( $ns, $dbkey );
915  $linkCache->addBadLinkObj( $title );
916  $this->mAllPages[$ns][$dbkey] = $this->mFakePageId;
917  $this->mMissingPages[$ns][$dbkey] = $this->mFakePageId;
918  $this->mGoodAndMissingPages[$ns][$dbkey] = $this->mFakePageId;
919  $this->mMissingTitles[$this->mFakePageId] = $title;
920  $this->mFakePageId--;
921  $this->mTitles[] = $title;
922 
923  // need gender information
924  if ( MWNamespace::hasGenderDistinction( $ns ) ) {
925  $usernames[] = $dbkey;
926  }
927  }
928  }
929  } else {
930  // The remaining pageids do not exist
931  if ( !$this->mMissingPageIDs ) {
932  $this->mMissingPageIDs = array_keys( $remaining );
933  } else {
934  $this->mMissingPageIDs = array_merge( $this->mMissingPageIDs, array_keys( $remaining ) );
935  }
936  }
937  }
938 
939  // Get gender information
940  $genderCache = MediaWikiServices::getInstance()->getGenderCache();
941  $genderCache->doQuery( $usernames, __METHOD__ );
942  }
943 
949  private function initFromRevIDs( $revids ) {
950  if ( !$revids ) {
951  return;
952  }
953 
954  $revids = array_map( 'intval', $revids ); // paranoia
955  $db = $this->getDB();
956  $pageids = [];
957  $remaining = array_flip( $revids );
958 
959  $revids = self::getPositiveIntegers( $revids );
960 
961  if ( !empty( $revids ) ) {
962  $tables = [ 'revision', 'page' ];
963  $fields = [ 'rev_id', 'rev_page' ];
964  $where = [ 'rev_id' => $revids, 'rev_page = page_id' ];
965 
966  // Get pageIDs data from the `page` table
967  $res = $db->select( $tables, $fields, $where, __METHOD__ );
968  foreach ( $res as $row ) {
969  $revid = intval( $row->rev_id );
970  $pageid = intval( $row->rev_page );
971  $this->mGoodRevIDs[$revid] = $pageid;
972  $this->mLiveRevIDs[$revid] = $pageid;
973  $pageids[$pageid] = '';
974  unset( $remaining[$revid] );
975  }
976  }
977 
978  $this->mMissingRevIDs = array_keys( $remaining );
979 
980  // Populate all the page information
981  $this->initFromPageIds( array_keys( $pageids ) );
982 
983  // If the user can see deleted revisions, pull out the corresponding
984  // titles from the archive table and include them too. We ignore
985  // ar_page_id because deleted revisions are tied by title, not page_id.
986  if ( !empty( $this->mMissingRevIDs ) && $this->getUser()->isAllowed( 'deletedhistory' ) ) {
987  $remaining = array_flip( $this->mMissingRevIDs );
988  $tables = [ 'archive' ];
989  $fields = [ 'ar_rev_id', 'ar_namespace', 'ar_title' ];
990  $where = [ 'ar_rev_id' => $this->mMissingRevIDs ];
991 
992  $res = $db->select( $tables, $fields, $where, __METHOD__ );
993  $titles = [];
994  foreach ( $res as $row ) {
995  $revid = intval( $row->ar_rev_id );
996  $titles[$revid] = Title::makeTitle( $row->ar_namespace, $row->ar_title );
997  unset( $remaining[$revid] );
998  }
999 
1000  $this->initFromTitles( $titles );
1001 
1002  foreach ( $titles as $revid => $title ) {
1003  $ns = $title->getNamespace();
1004  $dbkey = $title->getDBkey();
1005 
1006  // Handle converted titles
1007  if ( !isset( $this->mAllPages[$ns][$dbkey] ) &&
1008  isset( $this->mConvertedTitles[$title->getPrefixedText()] )
1009  ) {
1010  $title = Title::newFromText( $this->mConvertedTitles[$title->getPrefixedText()] );
1011  $ns = $title->getNamespace();
1012  $dbkey = $title->getDBkey();
1013  }
1014 
1015  if ( isset( $this->mAllPages[$ns][$dbkey] ) ) {
1016  $this->mGoodRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
1017  $this->mDeletedRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
1018  } else {
1019  $remaining[$revid] = true;
1020  }
1021  }
1022 
1023  $this->mMissingRevIDs = array_keys( $remaining );
1024  }
1025  }
1026 
1032  private function resolvePendingRedirects() {
1033  if ( $this->mResolveRedirects ) {
1034  $db = $this->getDB();
1035  $pageFlds = $this->getPageTableFields();
1036 
1037  // Repeat until all redirects have been resolved
1038  // The infinite loop is prevented by keeping all known pages in $this->mAllPages
1039  while ( $this->mPendingRedirectIDs || $this->mPendingRedirectSpecialPages ) {
1040  // Resolve redirects by querying the pagelinks table, and repeat the process
1041  // Create a new linkBatch object for the next pass
1042  $linkBatch = $this->getRedirectTargets();
1043 
1044  if ( $linkBatch->isEmpty() ) {
1045  break;
1046  }
1047 
1048  $set = $linkBatch->constructSet( 'page', $db );
1049  if ( $set === false ) {
1050  break;
1051  }
1052 
1053  // Get pageIDs data from the `page` table
1054  $res = $db->select( 'page', $pageFlds, $set, __METHOD__ );
1055 
1056  // Hack: get the ns:titles stored in [ns => array(titles)] format
1057  $this->initFromQueryResult( $res, $linkBatch->data, true );
1058  }
1059  }
1060  }
1061 
1069  private function getRedirectTargets() {
1070  $titlesToResolve = [];
1071  $db = $this->getDB();
1072 
1073  if ( $this->mPendingRedirectIDs ) {
1074  $res = $db->select(
1075  'redirect',
1076  [
1077  'rd_from',
1078  'rd_namespace',
1079  'rd_fragment',
1080  'rd_interwiki',
1081  'rd_title'
1082  ], [ 'rd_from' => array_keys( $this->mPendingRedirectIDs ) ],
1083  __METHOD__
1084  );
1085  foreach ( $res as $row ) {
1086  $rdfrom = intval( $row->rd_from );
1087  $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
1088  $to = Title::makeTitle(
1089  $row->rd_namespace,
1090  $row->rd_title,
1091  $row->rd_fragment,
1092  $row->rd_interwiki
1093  );
1094  $this->mResolvedRedirectTitles[$from] = $this->mPendingRedirectIDs[$rdfrom];
1095  unset( $this->mPendingRedirectIDs[$rdfrom] );
1096  if ( $to->isExternal() ) {
1097  $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
1098  } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
1099  $titlesToResolve[] = $to;
1100  }
1101  $this->mRedirectTitles[$from] = $to;
1102  }
1103 
1104  if ( $this->mPendingRedirectIDs ) {
1105  // We found pages that aren't in the redirect table
1106  // Add them
1107  foreach ( $this->mPendingRedirectIDs as $id => $title ) {
1109  $rt = $page->insertRedirect();
1110  if ( !$rt ) {
1111  // What the hell. Let's just ignore this
1112  continue;
1113  }
1114  if ( $rt->isExternal() ) {
1115  $this->mInterwikiTitles[$rt->getPrefixedText()] = $rt->getInterwiki();
1116  } elseif ( !isset( $this->mAllPages[$rt->getNamespace()][$rt->getDBkey()] ) ) {
1117  $titlesToResolve[] = $rt;
1118  }
1119  $from = $title->getPrefixedText();
1120  $this->mResolvedRedirectTitles[$from] = $title;
1121  $this->mRedirectTitles[$from] = $rt;
1122  unset( $this->mPendingRedirectIDs[$id] );
1123  }
1124  }
1125  }
1126 
1127  if ( $this->mPendingRedirectSpecialPages ) {
1128  foreach ( $this->mPendingRedirectSpecialPages as $key => list( $from, $to ) ) {
1129  $fromKey = $from->getPrefixedText();
1130  $this->mResolvedRedirectTitles[$fromKey] = $from;
1131  $this->mRedirectTitles[$fromKey] = $to;
1132  if ( $to->isExternal() ) {
1133  $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
1134  } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
1135  $titlesToResolve[] = $to;
1136  }
1137  }
1138  $this->mPendingRedirectSpecialPages = [];
1139 
1140  // Set private caching since we don't know what criteria the
1141  // special pages used to decide on these redirects.
1142  $this->mCacheMode = 'private';
1143  }
1144 
1145  return $this->processTitlesArray( $titlesToResolve );
1146  }
1147 
1161  public function getCacheMode( $params = null ) {
1162  return $this->mCacheMode;
1163  }
1164 
1174  private function processTitlesArray( $titles ) {
1175  $usernames = [];
1176  $linkBatch = new LinkBatch();
1177 
1178  foreach ( $titles as $title ) {
1179  if ( is_string( $title ) ) {
1180  try {
1181  $titleObj = Title::newFromTextThrow( $title, $this->mDefaultNamespace );
1182  } catch ( MalformedTitleException $ex ) {
1183  // Handle invalid titles gracefully
1184  if ( !isset( $this->mAllPages[0][$title] ) ) {
1185  $this->mAllPages[0][$title] = $this->mFakePageId;
1186  $this->mInvalidTitles[$this->mFakePageId] = [
1187  'title' => $title,
1188  'invalidreason' => $this->getErrorFormatter()->formatException( $ex, [ 'bc' => true ] ),
1189  ];
1190  $this->mFakePageId--;
1191  }
1192  continue; // There's nothing else we can do
1193  }
1194  } else {
1195  $titleObj = $title;
1196  }
1197  $unconvertedTitle = $titleObj->getPrefixedText();
1198  $titleWasConverted = false;
1199  if ( $titleObj->isExternal() ) {
1200  // This title is an interwiki link.
1201  $this->mInterwikiTitles[$unconvertedTitle] = $titleObj->getInterwiki();
1202  } else {
1203  // Variants checking
1205  if ( $this->mConvertTitles &&
1206  count( $wgContLang->getVariants() ) > 1 &&
1207  !$titleObj->exists()
1208  ) {
1209  // Language::findVariantLink will modify titleText and titleObj into
1210  // the canonical variant if possible
1211  $titleText = is_string( $title ) ? $title : $titleObj->getPrefixedText();
1212  $wgContLang->findVariantLink( $titleText, $titleObj );
1213  $titleWasConverted = $unconvertedTitle !== $titleObj->getPrefixedText();
1214  }
1215 
1216  if ( $titleObj->getNamespace() < 0 ) {
1217  // Handle Special and Media pages
1218  $titleObj = $titleObj->fixSpecialName();
1219  $ns = $titleObj->getNamespace();
1220  $dbkey = $titleObj->getDBkey();
1221  if ( !isset( $this->mAllSpecials[$ns][$dbkey] ) ) {
1222  $this->mAllSpecials[$ns][$dbkey] = $this->mFakePageId;
1223  $target = null;
1224  if ( $ns === NS_SPECIAL && $this->mResolveRedirects ) {
1226  if ( $special instanceof RedirectSpecialArticle ) {
1227  // Only RedirectSpecialArticle is intended to redirect to an article, other kinds of
1228  // RedirectSpecialPage are probably applying weird URL parameters we don't want to handle.
1229  $context = new DerivativeContext( $this );
1230  $context->setTitle( $titleObj );
1231  $context->setRequest( new FauxRequest );
1232  $special->setContext( $context );
1233  list( /* $alias */, $subpage ) = SpecialPageFactory::resolveAlias( $dbkey );
1234  $target = $special->getRedirect( $subpage );
1235  }
1236  }
1237  if ( $target ) {
1238  $this->mPendingRedirectSpecialPages[$dbkey] = [ $titleObj, $target ];
1239  } else {
1240  $this->mSpecialTitles[$this->mFakePageId] = $titleObj;
1241  $this->mFakePageId--;
1242  }
1243  }
1244  } else {
1245  // Regular page
1246  $linkBatch->addObj( $titleObj );
1247  }
1248  }
1249 
1250  // Make sure we remember the original title that was
1251  // given to us. This way the caller can correlate new
1252  // titles with the originally requested when e.g. the
1253  // namespace is localized or the capitalization is
1254  // different
1255  if ( $titleWasConverted ) {
1256  $this->mConvertedTitles[$unconvertedTitle] = $titleObj->getPrefixedText();
1257  // In this case the page can't be Special.
1258  if ( is_string( $title ) && $title !== $unconvertedTitle ) {
1259  $this->mNormalizedTitles[$title] = $unconvertedTitle;
1260  }
1261  } elseif ( is_string( $title ) && $title !== $titleObj->getPrefixedText() ) {
1262  $this->mNormalizedTitles[$title] = $titleObj->getPrefixedText();
1263  }
1264 
1265  // Need gender information
1266  if ( MWNamespace::hasGenderDistinction( $titleObj->getNamespace() ) ) {
1267  $usernames[] = $titleObj->getText();
1268  }
1269  }
1270  // Get gender information
1271  $genderCache = MediaWikiServices::getInstance()->getGenderCache();
1272  $genderCache->doQuery( $usernames, __METHOD__ );
1273 
1274  return $linkBatch;
1275  }
1276 
1292  public function setGeneratorData( Title $title, array $data ) {
1293  $ns = $title->getNamespace();
1294  $dbkey = $title->getDBkey();
1295  $this->mGeneratorData[$ns][$dbkey] = $data;
1296  }
1297 
1317  public function setRedirectMergePolicy( $callable ) {
1318  $this->mRedirectMergePolicy = $callable;
1319  }
1320 
1341  public function populateGeneratorData( &$result, array $path = [] ) {
1342  if ( $result instanceof ApiResult ) {
1343  $data = $result->getResultData( $path );
1344  if ( $data === null ) {
1345  return true;
1346  }
1347  } else {
1348  $data = &$result;
1349  foreach ( $path as $key ) {
1350  if ( !isset( $data[$key] ) ) {
1351  // Path isn't in $result, so nothing to add, so everything
1352  // "fits"
1353  return true;
1354  }
1355  $data = &$data[$key];
1356  }
1357  }
1358  foreach ( $this->mGeneratorData as $ns => $dbkeys ) {
1359  if ( $ns === -1 ) {
1360  $pages = [];
1361  foreach ( $this->mSpecialTitles as $id => $title ) {
1362  $pages[$title->getDBkey()] = $id;
1363  }
1364  } else {
1365  if ( !isset( $this->mAllPages[$ns] ) ) {
1366  // No known titles in the whole namespace. Skip it.
1367  continue;
1368  }
1369  $pages = $this->mAllPages[$ns];
1370  }
1371  foreach ( $dbkeys as $dbkey => $genData ) {
1372  if ( !isset( $pages[$dbkey] ) ) {
1373  // Unknown title. Forget it.
1374  continue;
1375  }
1376  $pageId = $pages[$dbkey];
1377  if ( !isset( $data[$pageId] ) ) {
1378  // $pageId didn't make it into the result. Ignore it.
1379  continue;
1380  }
1381 
1382  if ( $result instanceof ApiResult ) {
1383  $path2 = array_merge( $path, [ $pageId ] );
1384  foreach ( $genData as $key => $value ) {
1385  if ( !$result->addValue( $path2, $key, $value ) ) {
1386  return false;
1387  }
1388  }
1389  } else {
1390  $data[$pageId] = array_merge( $data[$pageId], $genData );
1391  }
1392  }
1393  }
1394 
1395  // Merge data generated about redirect titles into the redirect destination
1396  if ( $this->mRedirectMergePolicy ) {
1397  foreach ( $this->mResolvedRedirectTitles as $titleFrom ) {
1398  $dest = $titleFrom;
1399  while ( isset( $this->mRedirectTitles[$dest->getPrefixedText()] ) ) {
1400  $dest = $this->mRedirectTitles[$dest->getPrefixedText()];
1401  }
1402  $fromNs = $titleFrom->getNamespace();
1403  $fromDBkey = $titleFrom->getDBkey();
1404  $toPageId = $dest->getArticleID();
1405  if ( isset( $data[$toPageId] ) &&
1406  isset( $this->mGeneratorData[$fromNs][$fromDBkey] )
1407  ) {
1408  // It is necesary to set both $data and add to $result, if an ApiResult,
1409  // to ensure multiple redirects to the same destination are all merged.
1410  $data[$toPageId] = call_user_func(
1411  $this->mRedirectMergePolicy,
1412  $data[$toPageId],
1413  $this->mGeneratorData[$fromNs][$fromDBkey]
1414  );
1415  if ( $result instanceof ApiResult ) {
1416  if ( !$result->addValue( $path, $toPageId, $data[$toPageId], ApiResult::OVERRIDE ) ) {
1417  return false;
1418  }
1419  }
1420  }
1421  }
1422  }
1423 
1424  return true;
1425  }
1426 
1431  protected function getDB() {
1432  return $this->mDbSource->getDB();
1433  }
1434 
1441  private static function getPositiveIntegers( $array ) {
1442  // T27734 API: possible issue with revids validation
1443  // It seems with a load of revision rows, MySQL gets upset
1444  // Remove any < 0 integers, as they can't be valid
1445  foreach ( $array as $i => $int ) {
1446  if ( $int < 0 ) {
1447  unset( $array[$i] );
1448  }
1449  }
1450 
1451  return $array;
1452  }
1453 
1454  public function getAllowedParams( $flags = 0 ) {
1455  $result = [
1456  'titles' => [
1457  ApiBase::PARAM_ISMULTI => true,
1458  ApiBase::PARAM_HELP_MSG => 'api-pageset-param-titles',
1459  ],
1460  'pageids' => [
1461  ApiBase::PARAM_TYPE => 'integer',
1462  ApiBase::PARAM_ISMULTI => true,
1463  ApiBase::PARAM_HELP_MSG => 'api-pageset-param-pageids',
1464  ],
1465  'revids' => [
1466  ApiBase::PARAM_TYPE => 'integer',
1467  ApiBase::PARAM_ISMULTI => true,
1468  ApiBase::PARAM_HELP_MSG => 'api-pageset-param-revids',
1469  ],
1470  'generator' => [
1471  ApiBase::PARAM_TYPE => null,
1472  ApiBase::PARAM_HELP_MSG => 'api-pageset-param-generator',
1474  ],
1475  'redirects' => [
1476  ApiBase::PARAM_DFLT => false,
1477  ApiBase::PARAM_HELP_MSG => $this->mAllowGenerator
1478  ? 'api-pageset-param-redirects-generator'
1479  : 'api-pageset-param-redirects-nogenerator',
1480  ],
1481  'converttitles' => [
1482  ApiBase::PARAM_DFLT => false,
1484  'api-pageset-param-converttitles',
1485  [ Message::listParam( LanguageConverter::$languagesWithVariants, 'text' ) ],
1486  ],
1487  ],
1488  ];
1489 
1490  if ( !$this->mAllowGenerator ) {
1491  unset( $result['generator'] );
1492  } elseif ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
1493  $result['generator'][ApiBase::PARAM_TYPE] = 'submodule';
1494  $result['generator'][ApiBase::PARAM_SUBMODULE_MAP] = $this->getGenerators();
1495  }
1496 
1497  return $result;
1498  }
1499 
1500  protected function handleParamNormalization( $paramName, $value, $rawValue ) {
1501  parent::handleParamNormalization( $paramName, $value, $rawValue );
1502 
1503  if ( $paramName === 'titles' ) {
1504  // For the 'titles' parameter, we want to split it like ApiBase would
1505  // and add any changed titles to $this->mNormalizedTitles
1506  $value = $this->explodeMultiValue( $value, self::LIMIT_SML2 + 1 );
1507  $l = count( $value );
1508  $rawValue = $this->explodeMultiValue( $rawValue, $l );
1509  for ( $i = 0; $i < $l; $i++ ) {
1510  if ( $value[$i] !== $rawValue[$i] ) {
1511  $this->mNormalizedTitles[$rawValue[$i]] = $value[$i];
1512  }
1513  }
1514  }
1515  }
1516 
1517  private static $generators = null;
1518 
1523  private function getGenerators() {
1524  if ( self::$generators === null ) {
1526  if ( !( $query instanceof ApiQuery ) ) {
1527  // If the parent container of this pageset is not ApiQuery,
1528  // we must create it to get module manager
1529  $query = $this->getMain()->getModuleManager()->getModule( 'query' );
1530  }
1531  $gens = [];
1532  $prefix = $query->getModulePath() . '+';
1533  $mgr = $query->getModuleManager();
1534  foreach ( $mgr->getNamesWithClasses() as $name => $class ) {
1535  if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
1536  $gens[$name] = $prefix . $name;
1537  }
1538  }
1539  ksort( $gens );
1540  self::$generators = $gens;
1541  }
1542 
1543  return self::$generators;
1544  }
1545 }
ApiPageSet\$mPendingRedirectIDs
Title[] $mPendingRedirectIDs
Definition: ApiPageSet.php:73
ApiPageSet\$mConvertedTitles
$mConvertedTitles
Definition: ApiPageSet.php:76
ApiPageSet\getTitleCount
getTitleCount()
Returns the number of unique pages (not revisions) in the set.
Definition: ApiPageSet.php:363
ApiPageSet\$mRedirectTitles
$mRedirectTitles
Definition: ApiPageSet.php:67
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:34
ContextSource\getConfig
getConfig()
Get the Config object.
Definition: ContextSource.php:68
ApiBase\PARAM_SUBMODULE_MAP
const PARAM_SUBMODULE_MAP
(string[]) When PARAM_TYPE is 'submodule', map parameter values to submodule paths.
Definition: ApiBase.php:168
ApiPageSet\initFromTitles
initFromTitles( $titles)
This method populates internal variables with page information based on the given array of title stri...
Definition: ApiPageSet.php:813
ApiPageSet\$mSpecialTitles
$mSpecialTitles
Definition: ApiPageSet.php:68
FauxRequest
WebRequest clone which takes values from a provided array.
Definition: FauxRequest.php:33
ApiPageSet\$mMissingTitles
$mMissingTitles
Definition: ApiPageSet.php:63
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:265
ApiQuery
This is the main query class.
Definition: ApiQuery.php:40
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1720
ApiPageSet\processDbRow
processDbRow( $row)
Extract all requested fields from the row received from the database.
Definition: ApiPageSet.php:774
$tables
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist & $tables
Definition: hooks.txt:990
MWNamespace\hasGenderDistinction
static hasGenderDistinction( $index)
Does the namespace (potentially) have different aliases for different genders.
Definition: MWNamespace.php:411
ApiPageSet\$mResolveRedirects
$mResolveRedirects
Definition: ApiPageSet.php:53
LinkBatch
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:34
ApiPageSet\getGoodTitleCount
getGoodTitleCount()
Returns the number of found unique pages (not revisions) in the set.
Definition: ApiPageSet.php:387
ApiPageSet\processTitlesArray
processTitlesArray( $titles)
Given an array of title strings, convert them into Title objects.
Definition: ApiPageSet.php:1174
captcha-old.count
count
Definition: captcha-old.py:225
ApiPageSet\getTitles
getTitles()
All Title objects provided.
Definition: ApiPageSet.php:355
ApiPageSet\getConvertedTitles
getConvertedTitles()
Get a list of title conversions - maps a title to its converted version.
Definition: ApiPageSet.php:542
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1796
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:128
ApiPageSet\__construct
__construct(ApiBase $dbSource, $flags=0, $defaultNamespace=NS_MAIN)
Definition: ApiPageSet.php:121
ApiPageSet\getLiveRevisionIDs
getLiveRevisionIDs()
Get the list of non-deleted revision IDs (requested with the revids= parameter)
Definition: ApiPageSet.php:677
ApiPageSet\getInvalidTitles
getInvalidTitles()
Titles that were deemed invalid by Title::newFromText() The array's index will be unique and negative...
Definition: ApiPageSet.php:431
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language & $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED! Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language & $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1954
ApiBase\PARAM_TYPE
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below.
Definition: ApiBase.php:91
ApiPageSet\initFromQueryResult
initFromQueryResult( $res, &$remaining=null, $processTitles=null)
Iterate through the result of the query on 'page' table, and for each row create and store title obje...
Definition: ApiPageSet.php:878
ApiPageSet\requestField
requestField( $fieldName)
Request an additional field from the page table.
Definition: ApiPageSet.php:291
ApiPageSet\execute
execute()
Populate the PageSet from the request parameters.
Definition: ApiPageSet.php:143
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
ApiPageSet\$mDefaultNamespace
int $mDefaultNamespace
Definition: ApiPageSet.php:86
ApiPageSet\$mCacheMode
$mCacheMode
Definition: ApiPageSet.php:83
ApiPageSet\$mInterwikiTitles
$mInterwikiTitles
Definition: ApiPageSet.php:71
ApiPageSet\$mGoodPages
$mGoodPages
Definition: ApiPageSet.php:60
ApiPageSet\$mRedirectMergePolicy
callable null $mRedirectMergePolicy
Definition: ApiPageSet.php:88
$params
$params
Definition: styleTest.css.php:40
ApiPageSet\resolvePendingRedirects
resolvePendingRedirects()
Resolve any redirects in the result if redirect resolution was requested.
Definition: ApiPageSet.php:1032
ApiPageSet\getDeletedRevisionIDs
getDeletedRevisionIDs()
Get the list of revision IDs that were associated with deleted titles.
Definition: ApiPageSet.php:685
ApiPageSet\$mLiveRevIDs
$mLiveRevIDs
Definition: ApiPageSet.php:78
ApiPageSet\populateFromRevisionIDs
populateFromRevisionIDs( $revIDs)
Populate this PageSet from a list of revision IDs.
Definition: ApiPageSet.php:766
ApiPageSet\addValues
static addValues(array &$result, $values, $flags=[], $name=null)
Add all items from $values into the result.
Definition: ApiPageSet.php:97
ApiPageSet\$mConvertTitles
$mConvertTitles
Definition: ApiPageSet.php:54
$res
$res
Definition: database.txt:21
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:304
Wikimedia\Rdbms\ResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: ResultWrapper.php:24
ApiPageSet\$mGeneratorData
$mGeneratorData
Definition: ApiPageSet.php:81
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:133
ApiPageSet\$mMissingPages
$mMissingPages
Definition: ApiPageSet.php:62
ApiPageSet\getGoodAndMissingTitlesByNamespace
getGoodAndMissingTitlesByNamespace()
Returns an array [ns][dbkey] => page_id for all good and missing titles.
Definition: ApiPageSet.php:413
ApiPageSet\$mPendingRedirectSpecialPages
$mPendingRedirectSpecialPages
Definition: ApiPageSet.php:74
ApiPageSet\populateFromTitles
populateFromTitles( $titles)
Populate this PageSet from a list of Titles.
Definition: ApiPageSet.php:737
LinkCache\getSelectFields
static getSelectFields()
Fields that LinkCache needs to select.
Definition: LinkCache.php:213
ApiPageSet\setGeneratorData
setGeneratorData(Title $title, array $data)
Set data for a title.
Definition: ApiPageSet.php:1292
ApiPageSet\$mGoodRevIDs
$mGoodRevIDs
Definition: ApiPageSet.php:77
ApiPageSet
This class contains a list of pages that the client has requested.
Definition: ApiPageSet.php:44
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:41
ApiPageSet\executeDryRun
executeDryRun()
In case execute() is not called, call this method to mark all relevant parameters as used This preven...
Definition: ApiPageSet.php:136
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:40
ApiPageSet\getRedirectTitlesAsResult
getRedirectTitlesAsResult( $result=null)
Get a list of redirect resolutions - maps a title to its redirect target.
Definition: ApiPageSet.php:471
ApiPageSet\getPageTableFields
getPageTableFields()
Get the fields that have to be queried from the page table: the ones requested through requestField()...
Definition: ApiPageSet.php:311
ApiPageSet\$mInvalidTitles
array $mInvalidTitles
[fake_page_id] => [ 'title' => $title, 'invalidreason' => $reason ]
Definition: ApiPageSet.php:65
ApiPageSet\$mAllowGenerator
$mAllowGenerator
Definition: ApiPageSet.php:55
ApiPageSet\getConvertedTitlesAsResult
getConvertedTitlesAsResult( $result=null)
Get a list of title conversions - maps a title to its converted version as a result array.
Definition: ApiPageSet.php:553
ApiPageSet\$mParams
$mParams
Definition: ApiPageSet.php:52
NS_MAIN
const NS_MAIN
Definition: Defines.php:62
ApiPageSet\getMissingTitles
getMissingTitles()
Title objects that were NOT found in the database.
Definition: ApiPageSet.php:405
$query
null for the wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1572
ApiBase\explodeMultiValue
explodeMultiValue( $value, $limit)
Split a multi-valued parameter string, like explode()
Definition: ApiBase.php:1295
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:51
DerivativeContext
An IContextSource implementation which will inherit context from another source but allow individual ...
Definition: DerivativeContext.php:31
ApiPageSet\getMissingTitlesByNamespace
getMissingTitlesByNamespace()
Returns an array [ns][dbkey] => fake_page_id for all missing titles.
Definition: ApiPageSet.php:396
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:934
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:120
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1128
$titles
linkcache txt The LinkCache class maintains a list of article titles and the information about whether or not the article exists in the database This is used to mark up links when displaying a page If the same link appears more than once on any page then it only has to be looked up once In most cases link lookups are done in batches with the LinkBatch class or the equivalent in so the link cache is mostly useful for short snippets of parsed and for links in the navigation areas of the skin The link cache was formerly used to track links used in a document for the purposes of updating the link tables This application is now deprecated To create a you can use the following $titles
Definition: linkcache.txt:17
ApiPageSet\populateFromQueryResult
populateFromQueryResult( $db, $queryResult)
Populate this PageSet from a rowset returned from the database.
Definition: ApiPageSet.php:758
ApiResult
This class represents the result of the API operations.
Definition: ApiResult.php:33
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:453
ApiPageSet\$mGoodAndMissingPages
$mGoodAndMissingPages
Definition: ApiPageSet.php:59
$page
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached $page
Definition: hooks.txt:2536
ApiPageSet\getGenerators
getGenerators()
Get an array of all available generators.
Definition: ApiPageSet.php:1523
ApiPageSet\getDataSource
getDataSource()
Return the parameter name that is the source of data for this PageSet.
Definition: ApiPageSet.php:269
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:220
ApiPageSet\getRevisionIDs
getRevisionIDs()
Get the list of valid revision IDs (requested with the revids= parameter)
Definition: ApiPageSet.php:669
ApiPageSet\$mTitles
$mTitles
Definition: ApiPageSet.php:58
$generator
$generator
Definition: generateLocalAutoload.php:12
ApiPageSet\getRedirectTitles
getRedirectTitles()
Get a list of redirect resolutions - maps a title to its redirect target, as an array of output-ready...
Definition: ApiPageSet.php:460
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:514
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
ApiPageSet\getGoodTitles
getGoodTitles()
Title objects that were found in the database.
Definition: ApiPageSet.php:379
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
RedirectSpecialArticle
Superclass for any RedirectSpecialPage which redirects the user to a particular article (as opposed t...
Definition: RedirectSpecialPage.php:208
Title\newFromTextThrow
static newFromTextThrow( $text, $defaultNamespace=NS_MAIN)
Like Title::newFromText(), but throws MalformedTitleException when the title is invalid,...
Definition: Title.php:295
ApiPageSet\isResolvingRedirects
isResolvingRedirects()
Check whether this PageSet is resolving redirects.
Definition: ApiPageSet.php:257
ApiPageSet\$mGoodTitles
$mGoodTitles
Definition: ApiPageSet.php:61
ApiPageSet\getGoodAndMissingTitles
getGoodAndMissingTitles()
Title objects for good and missing titles.
Definition: ApiPageSet.php:421
ApiBase\extractRequestParams
extractRequestParams( $parseLimit=true)
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:718
ApiResult\setIndexedTagName
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:616
$value
$value
Definition: styleTest.css.php:45
ApiPageSet\getCacheMode
getCacheMode( $params=null)
Get the cache mode for the data generated by this module.
Definition: ApiPageSet.php:1161
ApiPageSet\initFromRevIDs
initFromRevIDs( $revids)
Does the same as initFromTitles(), but is based on revision IDs instead.
Definition: ApiPageSet.php:949
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:699
ApiBase\GET_VALUES_FOR_HELP
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When set, the result could take longer to generate, but should be more thoro...
Definition: ApiBase.php:216
ApiPageSet\getInterwikiTitles
getInterwikiTitles()
Get a list of interwiki titles - maps a title to its interwiki prefix.
Definition: ApiPageSet.php:573
ApiPageSet\getAllTitlesByNamespace
getAllTitlesByNamespace()
Returns an array [ns][dbkey] => page_id for all requested titles.
Definition: ApiPageSet.php:347
ApiPageSet\$mMissingRevIDs
$mMissingRevIDs
Definition: ApiPageSet.php:80
ApiPageSet\$generators
static $generators
Definition: ApiPageSet.php:1517
ApiPageSet\$mDbSource
$mDbSource
Definition: ApiPageSet.php:51
ApiPageSet\$mMissingPageIDs
$mMissingPageIDs
Definition: ApiPageSet.php:66
ApiPageSet\getNormalizedTitlesAsResult
getNormalizedTitlesAsResult( $result=null)
Get a list of title normalizations - maps a title to its normalized version in the form of result arr...
Definition: ApiPageSet.php:518
ApiPageSet\populateFromPageIDs
populateFromPageIDs( $pageIDs)
Populate this PageSet from a list of page IDs.
Definition: ApiPageSet.php:745
SpecialPageFactory\resolveAlias
static resolveAlias( $alias)
Given a special page name with a possible subpage, return an array where the first element is the spe...
Definition: SpecialPageFactory.php:338
ApiPageSet\getDB
getDB()
Get the database connection (read-only)
Definition: ApiPageSet.php:1431
ApiPageSet\getAllowedParams
getAllowedParams( $flags=0)
Definition: ApiPageSet.php:1454
ApiPageSet\getInterwikiTitlesAsResult
getInterwikiTitlesAsResult( $result=null, $iwUrl=false)
Get a list of interwiki titles - maps a title to its interwiki prefix as result.
Definition: ApiPageSet.php:585
ApiPageSet\getMissingPageIDs
getMissingPageIDs()
Page IDs that were not found in the database.
Definition: ApiPageSet.php:451
ApiPageSet\$mDeletedRevIDs
$mDeletedRevIDs
Definition: ApiPageSet.php:79
ApiPageSet\$mRequestedPageFields
$mRequestedPageFields
Definition: ApiPageSet.php:84
ApiPageSet\$mResolvedRedirectTitles
$mResolvedRedirectTitles
Definition: ApiPageSet.php:75
ApiPageSet\getRedirectTargets
getRedirectTargets()
Get the targets of the pending redirects from the database.
Definition: ApiPageSet.php:1069
ApiQueryGeneratorBase
Definition: ApiQueryGeneratorBase.php:30
Title
Represents a title within MediaWiki.
Definition: Title.php:39
ApiPageSet\getMissingRevisionIDsAsResult
getMissingRevisionIDsAsResult( $result=null)
Revision IDs that were not found in the database as result array.
Definition: ApiPageSet.php:703
MalformedTitleException
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Definition: MalformedTitleException.php:25
ApiPageSet\getInvalidTitlesAndRevisions
getInvalidTitlesAndRevisions( $invalidChecks=[ 'invalidTitles', 'special', 'missingIds', 'missingRevIds', 'missingTitles', 'interwikiTitles'])
Get an array of invalid/special/missing titles.
Definition: ApiPageSet.php:619
ApiPageSet\initFromPageIds
initFromPageIds( $pageids)
Does the same as initFromTitles(), but is based on page IDs instead.
Definition: ApiPageSet.php:840
ApiPageSet\getGoodTitlesByNamespace
getGoodTitlesByNamespace()
Returns an array [ns][dbkey] => page_id for all good titles.
Definition: ApiPageSet.php:371
LinkCache\singleton
static singleton()
Get an instance of this class.
Definition: LinkCache.php:67
ApiPageSet\executeInternal
executeInternal( $isDryRun)
Populate the PageSet from the request parameters.
Definition: ApiPageSet.php:152
ApiPageSet\handleParamNormalization
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition: ApiPageSet.php:1500
ApiPageSet\setRedirectMergePolicy
setRedirectMergePolicy( $callable)
Controls how generator data about a redirect source is merged into the generator data for the redirec...
Definition: ApiPageSet.php:1317
$path
$path
Definition: NoLocalSettings.php:26
ApiBase\PARAM_DFLT
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
Definition: ApiBase.php:52
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:490
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
Definition: ApiBase.php:55
ApiPageSet\getMissingRevisionIDs
getMissingRevisionIDs()
Revision IDs that were not found in the database.
Definition: ApiPageSet.php:693
ApiResult\OVERRIDE
const OVERRIDE
Override existing value in addValue(), setValue(), and similar functions.
Definition: ApiResult.php:39
ApiPageSet\getInvalidTitlesAndReasons
getInvalidTitlesAndReasons()
Titles that were deemed invalid by Title::newFromText() The array's index will be unique and negative...
Definition: ApiPageSet.php:443
$special
this hook is for auditing only RecentChangesLinked and Watchlist $special
Definition: hooks.txt:990
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:506
ApiPageSet\$mAllSpecials
$mAllSpecials
Definition: ApiPageSet.php:69
SpecialPageFactory\getPage
static getPage( $name)
Find the object with a given name and return it (or NULL)
Definition: SpecialPageFactory.php:379
$t
$t
Definition: testCompression.php:67
ApiPageSet\getCustomField
getCustomField( $fieldName)
Get the value of a custom field previously requested through requestField()
Definition: ApiPageSet.php:301
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
ApiPageSet\getRevisionCount
getRevisionCount()
Returns the number of revisions (requested with revids= parameter).
Definition: ApiPageSet.php:729
ApiPageSet\$mAllPages
$mAllPages
Definition: ApiPageSet.php:57
ApiBase\PARAM_SUBMODULE_PARAM_PREFIX
const PARAM_SUBMODULE_PARAM_PREFIX
(string) When PARAM_TYPE is 'submodule', used to indicate the 'g' prefix added by ApiQueryGeneratorBa...
Definition: ApiBase.php:175
ApiPageSet\DISABLE_GENERATORS
const DISABLE_GENERATORS
Constructor flag: The new instance of ApiPageSet will ignore the 'generator=' parameter.
Definition: ApiPageSet.php:49
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
ApiPageSet\$mFakePageId
$mFakePageId
Definition: ApiPageSet.php:82
ApiPageSet\getSpecialTitles
getSpecialTitles()
Get the list of titles with negative namespace.
Definition: ApiPageSet.php:721
ApiPageSet\getNormalizedTitles
getNormalizedTitles()
Get a list of title normalizations - maps a title to its normalized version.
Definition: ApiPageSet.php:507
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1962
ApiPageSet\$mNormalizedTitles
$mNormalizedTitles
Definition: ApiPageSet.php:70
ApiBase\getErrorFormatter
getErrorFormatter()
Get the error formatter.
Definition: ApiBase.php:624
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2749
ApiPageSet\populateGeneratorData
populateGeneratorData(&$result, array $path=[])
Populate the generator data for all titles in the result.
Definition: ApiPageSet.php:1341
ApiQueryBase\addTitleInfo
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
Definition: ApiQueryBase.php:486
array
the array() calling protocol came about after MediaWiki 1.4rc1.
ApiPageSet\getPositiveIntegers
static getPositiveIntegers( $array)
Returns the input array of integers with all values < 0 removed.
Definition: ApiPageSet.php:1441
$wgContLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
Definition: design.txt:56