MediaWiki REL1_31
ApiPageSet.php
Go to the documentation of this file.
1<?php
25
40class ApiPageSet extends ApiBase {
46
47 private $mDbSource;
48 private $mParams;
52
53 private $mAllPages = []; // [ns][dbkey] => page_id or negative when missing
54 private $mTitles = [];
55 private $mGoodAndMissingPages = []; // [ns][dbkey] => page_id or negative when missing
56 private $mGoodPages = []; // [ns][dbkey] => page_id
57 private $mGoodTitles = [];
58 private $mMissingPages = []; // [ns][dbkey] => fake page_id
59 private $mMissingTitles = [];
61 private $mInvalidTitles = [];
62 private $mMissingPageIDs = [];
63 private $mRedirectTitles = [];
64 private $mSpecialTitles = [];
65 private $mAllSpecials = []; // separate from mAllPages to avoid breaking getAllTitlesByNamespace()
66 private $mNormalizedTitles = [];
67 private $mInterwikiTitles = [];
70 private $mPendingRedirectSpecialPages = []; // [dbkey] => [ Title $from, Title $to ]
72 private $mConvertedTitles = [];
73 private $mGoodRevIDs = [];
74 private $mLiveRevIDs = [];
75 private $mDeletedRevIDs = [];
76 private $mMissingRevIDs = [];
77 private $mGeneratorData = []; // [ns][dbkey] => data array
78 private $mFakePageId = -1;
79 private $mCacheMode = 'public';
85
93 private static function addValues( array &$result, $values, $flags = [], $name = null ) {
94 foreach ( $values as $val ) {
95 if ( $val instanceof Title ) {
96 $v = [];
98 } elseif ( $name !== null ) {
99 $v = [ $name => $val ];
100 } else {
101 $v = $val;
102 }
103 foreach ( $flags as $flag ) {
104 $v[$flag] = true;
105 }
106 $result[] = $v;
107 }
108 }
109
117 public function __construct( ApiBase $dbSource, $flags = 0, $defaultNamespace = NS_MAIN ) {
118 parent::__construct( $dbSource->getMain(), $dbSource->getModuleName() );
119 $this->mDbSource = $dbSource;
120 $this->mAllowGenerator = ( $flags & self::DISABLE_GENERATORS ) == 0;
121 $this->mDefaultNamespace = $defaultNamespace;
122
123 $this->mParams = $this->extractRequestParams();
124 $this->mResolveRedirects = $this->mParams['redirects'];
125 $this->mConvertTitles = $this->mParams['converttitles'];
126 }
127
132 public function executeDryRun() {
133 $this->executeInternal( true );
134 }
135
139 public function execute() {
140 $this->executeInternal( false );
141 }
142
148 private function executeInternal( $isDryRun ) {
149 $generatorName = $this->mAllowGenerator ? $this->mParams['generator'] : null;
150 if ( isset( $generatorName ) ) {
151 $dbSource = $this->mDbSource;
152 if ( !$dbSource instanceof ApiQuery ) {
153 // If the parent container of this pageset is not ApiQuery, we must create it to run generator
154 $dbSource = $this->getMain()->getModuleManager()->getModule( 'query' );
155 }
156 $generator = $dbSource->getModuleManager()->getModule( $generatorName, null, true );
157 if ( $generator === null ) {
158 $this->dieWithError( [ 'apierror-badgenerator-unknown', $generatorName ], 'badgenerator' );
159 }
160 if ( !$generator instanceof ApiQueryGeneratorBase ) {
161 $this->dieWithError( [ 'apierror-badgenerator-notgenerator', $generatorName ], 'badgenerator' );
162 }
163 // Create a temporary pageset to store generator's output,
164 // add any additional fields generator may need, and execute pageset to populate titles/pageids
165 $tmpPageSet = new ApiPageSet( $dbSource, self::DISABLE_GENERATORS );
166 $generator->setGeneratorMode( $tmpPageSet );
167 $this->mCacheMode = $generator->getCacheMode( $generator->extractRequestParams() );
168
169 if ( !$isDryRun ) {
170 $generator->requestExtraData( $tmpPageSet );
171 }
172 $tmpPageSet->executeInternal( $isDryRun );
173
174 // populate this pageset with the generator output
175 if ( !$isDryRun ) {
176 $generator->executeGenerator( $this );
177
178 // Avoid PHP 7.1 warning of passing $this by reference
179 $apiModule = $this;
180 Hooks::run( 'APIQueryGeneratorAfterExecute', [ &$generator, &$apiModule ] );
181 } else {
182 // Prevent warnings from being reported on these parameters
183 $main = $this->getMain();
184 foreach ( $generator->extractRequestParams() as $paramName => $param ) {
185 $main->markParamsUsed( $generator->encodeParamName( $paramName ) );
186 }
187 }
188
189 if ( !$isDryRun ) {
191 }
192 } else {
193 // Only one of the titles/pageids/revids is allowed at the same time
194 $dataSource = null;
195 if ( isset( $this->mParams['titles'] ) ) {
196 $dataSource = 'titles';
197 }
198 if ( isset( $this->mParams['pageids'] ) ) {
199 if ( isset( $dataSource ) ) {
200 $this->dieWithError(
201 [
202 'apierror-invalidparammix-cannotusewith',
203 $this->encodeParamName( 'pageids' ),
204 $this->encodeParamName( $dataSource )
205 ],
206 'multisource'
207 );
208 }
209 $dataSource = 'pageids';
210 }
211 if ( isset( $this->mParams['revids'] ) ) {
212 if ( isset( $dataSource ) ) {
213 $this->dieWithError(
214 [
215 'apierror-invalidparammix-cannotusewith',
216 $this->encodeParamName( 'revids' ),
217 $this->encodeParamName( $dataSource )
218 ],
219 'multisource'
220 );
221 }
222 $dataSource = 'revids';
223 }
224
225 if ( !$isDryRun ) {
226 // Populate page information with the original user input
227 switch ( $dataSource ) {
228 case 'titles':
229 $this->initFromTitles( $this->mParams['titles'] );
230 break;
231 case 'pageids':
232 $this->initFromPageIds( $this->mParams['pageids'] );
233 break;
234 case 'revids':
235 if ( $this->mResolveRedirects ) {
236 $this->addWarning( 'apiwarn-redirectsandrevids' );
237 }
238 $this->mResolveRedirects = false;
239 $this->initFromRevIDs( $this->mParams['revids'] );
240 break;
241 default:
242 // Do nothing - some queries do not need any of the data sources.
243 break;
244 }
245 }
246 }
247 }
248
253 public function isResolvingRedirects() {
255 }
256
265 public function getDataSource() {
266 if ( $this->mAllowGenerator && isset( $this->mParams['generator'] ) ) {
267 return 'generator';
268 }
269 if ( isset( $this->mParams['titles'] ) ) {
270 return 'titles';
271 }
272 if ( isset( $this->mParams['pageids'] ) ) {
273 return 'pageids';
274 }
275 if ( isset( $this->mParams['revids'] ) ) {
276 return 'revids';
277 }
278
279 return null;
280 }
281
287 public function requestField( $fieldName ) {
288 $this->mRequestedPageFields[$fieldName] = null;
289 }
290
297 public function getCustomField( $fieldName ) {
298 return $this->mRequestedPageFields[$fieldName];
299 }
300
307 public function getPageTableFields() {
308 // Ensure we get minimum required fields
309 // DON'T change this order
310 $pageFlds = [
311 'page_namespace' => null,
312 'page_title' => null,
313 'page_id' => null,
314 ];
315
316 if ( $this->mResolveRedirects ) {
317 $pageFlds['page_is_redirect'] = null;
318 }
319
320 if ( $this->getConfig()->get( 'ContentHandlerUseDB' ) ) {
321 $pageFlds['page_content_model'] = null;
322 }
323
324 if ( $this->getConfig()->get( 'PageLanguageUseDB' ) ) {
325 $pageFlds['page_lang'] = null;
326 }
327
328 foreach ( LinkCache::getSelectFields() as $field ) {
329 $pageFlds[$field] = null;
330 }
331
332 $pageFlds = array_merge( $pageFlds, $this->mRequestedPageFields );
333
334 return array_keys( $pageFlds );
335 }
336
343 public function getAllTitlesByNamespace() {
344 return $this->mAllPages;
345 }
346
351 public function getTitles() {
352 return $this->mTitles;
353 }
354
359 public function getTitleCount() {
360 return count( $this->mTitles );
361 }
362
367 public function getGoodTitlesByNamespace() {
368 return $this->mGoodPages;
369 }
370
375 public function getGoodTitles() {
376 return $this->mGoodTitles;
377 }
378
383 public function getGoodTitleCount() {
384 return count( $this->mGoodTitles );
385 }
386
392 public function getMissingTitlesByNamespace() {
394 }
395
401 public function getMissingTitles() {
403 }
404
412
417 public function getGoodAndMissingTitles() {
418 return $this->mGoodTitles + $this->mMissingTitles;
419 }
420
427 public function getInvalidTitles() {
428 wfDeprecated( __METHOD__, '1.26' );
429 return array_map( function ( $t ) {
430 return $t['title'];
432 }
433
439 public function getInvalidTitlesAndReasons() {
441 }
442
447 public function getMissingPageIDs() {
449 }
450
456 public function getRedirectTitles() {
458 }
459
467 public function getRedirectTitlesAsResult( $result = null ) {
468 $values = [];
469 foreach ( $this->getRedirectTitles() as $titleStrFrom => $titleTo ) {
470 $r = [
471 'from' => strval( $titleStrFrom ),
472 'to' => $titleTo->getPrefixedText(),
473 ];
474 if ( $titleTo->hasFragment() ) {
475 $r['tofragment'] = $titleTo->getFragment();
476 }
477 if ( $titleTo->isExternal() ) {
478 $r['tointerwiki'] = $titleTo->getInterwiki();
479 }
480 if ( isset( $this->mResolvedRedirectTitles[$titleStrFrom] ) ) {
481 $titleFrom = $this->mResolvedRedirectTitles[$titleStrFrom];
482 $ns = $titleFrom->getNamespace();
483 $dbkey = $titleFrom->getDBkey();
484 if ( isset( $this->mGeneratorData[$ns][$dbkey] ) ) {
485 $r = array_merge( $this->mGeneratorData[$ns][$dbkey], $r );
486 }
487 }
488
489 $values[] = $r;
490 }
491 if ( !empty( $values ) && $result ) {
492 ApiResult::setIndexedTagName( $values, 'r' );
493 }
494
495 return $values;
496 }
497
503 public function getNormalizedTitles() {
505 }
506
514 public function getNormalizedTitlesAsResult( $result = null ) {
515 global $wgContLang;
516
517 $values = [];
518 foreach ( $this->getNormalizedTitles() as $rawTitleStr => $titleStr ) {
519 $encode = ( $wgContLang->normalize( $rawTitleStr ) !== $rawTitleStr );
520 $values[] = [
521 'fromencoded' => $encode,
522 'from' => $encode ? rawurlencode( $rawTitleStr ) : $rawTitleStr,
523 'to' => $titleStr
524 ];
525 }
526 if ( !empty( $values ) && $result ) {
527 ApiResult::setIndexedTagName( $values, 'n' );
528 }
529
530 return $values;
531 }
532
538 public function getConvertedTitles() {
540 }
541
549 public function getConvertedTitlesAsResult( $result = null ) {
550 $values = [];
551 foreach ( $this->getConvertedTitles() as $rawTitleStr => $titleStr ) {
552 $values[] = [
553 'from' => $rawTitleStr,
554 'to' => $titleStr
555 ];
556 }
557 if ( !empty( $values ) && $result ) {
558 ApiResult::setIndexedTagName( $values, 'c' );
559 }
560
561 return $values;
562 }
563
569 public function getInterwikiTitles() {
571 }
572
581 public function getInterwikiTitlesAsResult( $result = null, $iwUrl = false ) {
582 $values = [];
583 foreach ( $this->getInterwikiTitles() as $rawTitleStr => $interwikiStr ) {
584 $item = [
585 'title' => $rawTitleStr,
586 'iw' => $interwikiStr,
587 ];
588 if ( $iwUrl ) {
589 $title = Title::newFromText( $rawTitleStr );
590 $item['url'] = $title->getFullURL( '', false, PROTO_CURRENT );
591 }
592 $values[] = $item;
593 }
594 if ( !empty( $values ) && $result ) {
595 ApiResult::setIndexedTagName( $values, 'i' );
596 }
597
598 return $values;
599 }
600
615 public function getInvalidTitlesAndRevisions( $invalidChecks = [ 'invalidTitles',
616 'special', 'missingIds', 'missingRevIds', 'missingTitles', 'interwikiTitles' ]
617 ) {
618 $result = [];
619 if ( in_array( 'invalidTitles', $invalidChecks ) ) {
620 self::addValues( $result, $this->getInvalidTitlesAndReasons(), [ 'invalid' ] );
621 }
622 if ( in_array( 'special', $invalidChecks ) ) {
623 $known = [];
624 $unknown = [];
625 foreach ( $this->getSpecialTitles() as $title ) {
626 if ( $title->isKnown() ) {
627 $known[] = $title;
628 } else {
629 $unknown[] = $title;
630 }
631 }
632 self::addValues( $result, $unknown, [ 'special', 'missing' ] );
633 self::addValues( $result, $known, [ 'special' ] );
634 }
635 if ( in_array( 'missingIds', $invalidChecks ) ) {
636 self::addValues( $result, $this->getMissingPageIDs(), [ 'missing' ], 'pageid' );
637 }
638 if ( in_array( 'missingRevIds', $invalidChecks ) ) {
639 self::addValues( $result, $this->getMissingRevisionIDs(), [ 'missing' ], 'revid' );
640 }
641 if ( in_array( 'missingTitles', $invalidChecks ) ) {
642 $known = [];
643 $unknown = [];
644 foreach ( $this->getMissingTitles() as $title ) {
645 if ( $title->isKnown() ) {
646 $known[] = $title;
647 } else {
648 $unknown[] = $title;
649 }
650 }
651 self::addValues( $result, $unknown, [ 'missing' ] );
652 self::addValues( $result, $known, [ 'missing', 'known' ] );
653 }
654 if ( in_array( 'interwikiTitles', $invalidChecks ) ) {
655 self::addValues( $result, $this->getInterwikiTitlesAsResult() );
656 }
657
658 return $result;
659 }
660
665 public function getRevisionIDs() {
666 return $this->mGoodRevIDs;
667 }
668
673 public function getLiveRevisionIDs() {
674 return $this->mLiveRevIDs;
675 }
676
681 public function getDeletedRevisionIDs() {
683 }
684
689 public function getMissingRevisionIDs() {
691 }
692
699 public function getMissingRevisionIDsAsResult( $result = null ) {
700 $values = [];
701 foreach ( $this->getMissingRevisionIDs() as $revid ) {
702 $values[$revid] = [
703 'revid' => $revid
704 ];
705 }
706 if ( !empty( $values ) && $result ) {
707 ApiResult::setIndexedTagName( $values, 'rev' );
708 }
709
710 return $values;
711 }
712
717 public function getSpecialTitles() {
719 }
720
725 public function getRevisionCount() {
726 return count( $this->getRevisionIDs() );
727 }
728
733 public function populateFromTitles( $titles ) {
734 $this->initFromTitles( $titles );
735 }
736
741 public function populateFromPageIDs( $pageIDs ) {
742 $this->initFromPageIds( $pageIDs );
743 }
744
754 public function populateFromQueryResult( $db, $queryResult ) {
755 $this->initFromQueryResult( $queryResult );
756 }
757
762 public function populateFromRevisionIDs( $revIDs ) {
763 $this->initFromRevIDs( $revIDs );
764 }
765
770 public function processDbRow( $row ) {
771 // Store Title object in various data structures
772 $title = Title::newFromRow( $row );
773
774 LinkCache::singleton()->addGoodLinkObjFromRow( $title, $row );
775
776 $pageId = intval( $row->page_id );
777 $this->mAllPages[$row->page_namespace][$row->page_title] = $pageId;
778 $this->mTitles[] = $title;
779
780 if ( $this->mResolveRedirects && $row->page_is_redirect == '1' ) {
781 $this->mPendingRedirectIDs[$pageId] = $title;
782 } else {
783 $this->mGoodPages[$row->page_namespace][$row->page_title] = $pageId;
784 $this->mGoodAndMissingPages[$row->page_namespace][$row->page_title] = $pageId;
785 $this->mGoodTitles[$pageId] = $title;
786 }
787
788 foreach ( $this->mRequestedPageFields as $fieldName => &$fieldValues ) {
789 $fieldValues[$pageId] = $row->$fieldName;
790 }
791 }
792
809 private function initFromTitles( $titles ) {
810 // Get validated and normalized title objects
811 $linkBatch = $this->processTitlesArray( $titles );
812 if ( $linkBatch->isEmpty() ) {
813 // There might be special-page redirects
815 return;
816 }
817
818 $db = $this->getDB();
819 $set = $linkBatch->constructSet( 'page', $db );
820
821 // Get pageIDs data from the `page` table
822 $res = $db->select( 'page', $this->getPageTableFields(), $set,
823 __METHOD__ );
824
825 // Hack: get the ns:titles stored in [ ns => [ titles ] ] format
826 $this->initFromQueryResult( $res, $linkBatch->data, true ); // process Titles
827
828 // Resolve any found redirects
830 }
831
836 private function initFromPageIds( $pageids ) {
837 if ( !$pageids ) {
838 return;
839 }
840
841 $pageids = array_map( 'intval', $pageids ); // paranoia
842 $remaining = array_flip( $pageids );
843
844 $pageids = self::getPositiveIntegers( $pageids );
845
846 $res = null;
847 if ( !empty( $pageids ) ) {
848 $set = [
849 'page_id' => $pageids
850 ];
851 $db = $this->getDB();
852
853 // Get pageIDs data from the `page` table
854 $res = $db->select( 'page', $this->getPageTableFields(), $set,
855 __METHOD__ );
856 }
857
858 $this->initFromQueryResult( $res, $remaining, false ); // process PageIDs
859
860 // Resolve any found redirects
862 }
863
874 private function initFromQueryResult( $res, &$remaining = null, $processTitles = null ) {
875 if ( !is_null( $remaining ) && is_null( $processTitles ) ) {
876 ApiBase::dieDebug( __METHOD__, 'Missing $processTitles parameter when $remaining is provided' );
877 }
878
879 $usernames = [];
880 if ( $res ) {
881 foreach ( $res as $row ) {
882 $pageId = intval( $row->page_id );
883
884 // Remove found page from the list of remaining items
885 if ( isset( $remaining ) ) {
886 if ( $processTitles ) {
887 unset( $remaining[$row->page_namespace][$row->page_title] );
888 } else {
889 unset( $remaining[$pageId] );
890 }
891 }
892
893 // Store any extra fields requested by modules
894 $this->processDbRow( $row );
895
896 // Need gender information
897 if ( MWNamespace::hasGenderDistinction( $row->page_namespace ) ) {
898 $usernames[] = $row->page_title;
899 }
900 }
901 }
902
903 if ( isset( $remaining ) ) {
904 // Any items left in the $remaining list are added as missing
905 if ( $processTitles ) {
906 // The remaining titles in $remaining are non-existent pages
907 $linkCache = LinkCache::singleton();
908 foreach ( $remaining as $ns => $dbkeys ) {
909 foreach ( array_keys( $dbkeys ) as $dbkey ) {
910 $title = Title::makeTitle( $ns, $dbkey );
911 $linkCache->addBadLinkObj( $title );
912 $this->mAllPages[$ns][$dbkey] = $this->mFakePageId;
913 $this->mMissingPages[$ns][$dbkey] = $this->mFakePageId;
914 $this->mGoodAndMissingPages[$ns][$dbkey] = $this->mFakePageId;
915 $this->mMissingTitles[$this->mFakePageId] = $title;
916 $this->mFakePageId--;
917 $this->mTitles[] = $title;
918
919 // need gender information
920 if ( MWNamespace::hasGenderDistinction( $ns ) ) {
921 $usernames[] = $dbkey;
922 }
923 }
924 }
925 } else {
926 // The remaining pageids do not exist
927 if ( !$this->mMissingPageIDs ) {
928 $this->mMissingPageIDs = array_keys( $remaining );
929 } else {
930 $this->mMissingPageIDs = array_merge( $this->mMissingPageIDs, array_keys( $remaining ) );
931 }
932 }
933 }
934
935 // Get gender information
936 $genderCache = MediaWikiServices::getInstance()->getGenderCache();
937 $genderCache->doQuery( $usernames, __METHOD__ );
938 }
939
945 private function initFromRevIDs( $revids ) {
946 if ( !$revids ) {
947 return;
948 }
949
950 $revids = array_map( 'intval', $revids ); // paranoia
951 $db = $this->getDB();
952 $pageids = [];
953 $remaining = array_flip( $revids );
954
955 $revids = self::getPositiveIntegers( $revids );
956
957 if ( !empty( $revids ) ) {
958 $tables = [ 'revision', 'page' ];
959 $fields = [ 'rev_id', 'rev_page' ];
960 $where = [ 'rev_id' => $revids, 'rev_page = page_id' ];
961
962 // Get pageIDs data from the `page` table
963 $res = $db->select( $tables, $fields, $where, __METHOD__ );
964 foreach ( $res as $row ) {
965 $revid = intval( $row->rev_id );
966 $pageid = intval( $row->rev_page );
967 $this->mGoodRevIDs[$revid] = $pageid;
968 $this->mLiveRevIDs[$revid] = $pageid;
969 $pageids[$pageid] = '';
970 unset( $remaining[$revid] );
971 }
972 }
973
974 $this->mMissingRevIDs = array_keys( $remaining );
975
976 // Populate all the page information
977 $this->initFromPageIds( array_keys( $pageids ) );
978
979 // If the user can see deleted revisions, pull out the corresponding
980 // titles from the archive table and include them too. We ignore
981 // ar_page_id because deleted revisions are tied by title, not page_id.
982 if ( !empty( $this->mMissingRevIDs ) && $this->getUser()->isAllowed( 'deletedhistory' ) ) {
983 $remaining = array_flip( $this->mMissingRevIDs );
984 $tables = [ 'archive' ];
985 $fields = [ 'ar_rev_id', 'ar_namespace', 'ar_title' ];
986 $where = [ 'ar_rev_id' => $this->mMissingRevIDs ];
987
988 $res = $db->select( $tables, $fields, $where, __METHOD__ );
989 $titles = [];
990 foreach ( $res as $row ) {
991 $revid = intval( $row->ar_rev_id );
992 $titles[$revid] = Title::makeTitle( $row->ar_namespace, $row->ar_title );
993 unset( $remaining[$revid] );
994 }
995
996 $this->initFromTitles( $titles );
997
998 foreach ( $titles as $revid => $title ) {
999 $ns = $title->getNamespace();
1000 $dbkey = $title->getDBkey();
1001
1002 // Handle converted titles
1003 if ( !isset( $this->mAllPages[$ns][$dbkey] ) &&
1004 isset( $this->mConvertedTitles[$title->getPrefixedText()] )
1005 ) {
1006 $title = Title::newFromText( $this->mConvertedTitles[$title->getPrefixedText()] );
1007 $ns = $title->getNamespace();
1008 $dbkey = $title->getDBkey();
1009 }
1010
1011 if ( isset( $this->mAllPages[$ns][$dbkey] ) ) {
1012 $this->mGoodRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
1013 $this->mDeletedRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
1014 } else {
1015 $remaining[$revid] = true;
1016 }
1017 }
1018
1019 $this->mMissingRevIDs = array_keys( $remaining );
1020 }
1021 }
1022
1028 private function resolvePendingRedirects() {
1029 if ( $this->mResolveRedirects ) {
1030 $db = $this->getDB();
1031 $pageFlds = $this->getPageTableFields();
1032
1033 // Repeat until all redirects have been resolved
1034 // The infinite loop is prevented by keeping all known pages in $this->mAllPages
1035 while ( $this->mPendingRedirectIDs || $this->mPendingRedirectSpecialPages ) {
1036 // Resolve redirects by querying the pagelinks table, and repeat the process
1037 // Create a new linkBatch object for the next pass
1038 $linkBatch = $this->getRedirectTargets();
1039
1040 if ( $linkBatch->isEmpty() ) {
1041 break;
1042 }
1043
1044 $set = $linkBatch->constructSet( 'page', $db );
1045 if ( $set === false ) {
1046 break;
1047 }
1048
1049 // Get pageIDs data from the `page` table
1050 $res = $db->select( 'page', $pageFlds, $set, __METHOD__ );
1051
1052 // Hack: get the ns:titles stored in [ns => array(titles)] format
1053 $this->initFromQueryResult( $res, $linkBatch->data, true );
1054 }
1055 }
1056 }
1057
1065 private function getRedirectTargets() {
1066 $titlesToResolve = [];
1067 $db = $this->getDB();
1068
1069 if ( $this->mPendingRedirectIDs ) {
1070 $res = $db->select(
1071 'redirect',
1072 [
1073 'rd_from',
1074 'rd_namespace',
1075 'rd_fragment',
1076 'rd_interwiki',
1077 'rd_title'
1078 ], [ 'rd_from' => array_keys( $this->mPendingRedirectIDs ) ],
1079 __METHOD__
1080 );
1081 foreach ( $res as $row ) {
1082 $rdfrom = intval( $row->rd_from );
1083 $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
1084 $to = Title::makeTitle(
1085 $row->rd_namespace,
1086 $row->rd_title,
1087 $row->rd_fragment,
1088 $row->rd_interwiki
1089 );
1090 $this->mResolvedRedirectTitles[$from] = $this->mPendingRedirectIDs[$rdfrom];
1091 unset( $this->mPendingRedirectIDs[$rdfrom] );
1092 if ( $to->isExternal() ) {
1093 $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
1094 } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
1095 $titlesToResolve[] = $to;
1096 }
1097 $this->mRedirectTitles[$from] = $to;
1098 }
1099
1100 if ( $this->mPendingRedirectIDs ) {
1101 // We found pages that aren't in the redirect table
1102 // Add them
1103 foreach ( $this->mPendingRedirectIDs as $id => $title ) {
1104 $page = WikiPage::factory( $title );
1105 $rt = $page->insertRedirect();
1106 if ( !$rt ) {
1107 // What the hell. Let's just ignore this
1108 continue;
1109 }
1110 if ( $rt->isExternal() ) {
1111 $this->mInterwikiTitles[$rt->getPrefixedText()] = $rt->getInterwiki();
1112 } elseif ( !isset( $this->mAllPages[$rt->getNamespace()][$rt->getDBkey()] ) ) {
1113 $titlesToResolve[] = $rt;
1114 }
1115 $from = $title->getPrefixedText();
1116 $this->mResolvedRedirectTitles[$from] = $title;
1117 $this->mRedirectTitles[$from] = $rt;
1118 unset( $this->mPendingRedirectIDs[$id] );
1119 }
1120 }
1121 }
1122
1123 if ( $this->mPendingRedirectSpecialPages ) {
1124 foreach ( $this->mPendingRedirectSpecialPages as $key => list( $from, $to ) ) {
1125 $fromKey = $from->getPrefixedText();
1126 $this->mResolvedRedirectTitles[$fromKey] = $from;
1127 $this->mRedirectTitles[$fromKey] = $to;
1128 if ( $to->isExternal() ) {
1129 $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
1130 } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
1131 $titlesToResolve[] = $to;
1132 }
1133 }
1134 $this->mPendingRedirectSpecialPages = [];
1135
1136 // Set private caching since we don't know what criteria the
1137 // special pages used to decide on these redirects.
1138 $this->mCacheMode = 'private';
1139 }
1140
1141 return $this->processTitlesArray( $titlesToResolve );
1142 }
1143
1157 public function getCacheMode( $params = null ) {
1158 return $this->mCacheMode;
1159 }
1160
1170 private function processTitlesArray( $titles ) {
1171 $usernames = [];
1172 $linkBatch = new LinkBatch();
1173
1174 foreach ( $titles as $title ) {
1175 if ( is_string( $title ) ) {
1176 try {
1177 $titleObj = Title::newFromTextThrow( $title, $this->mDefaultNamespace );
1178 } catch ( MalformedTitleException $ex ) {
1179 // Handle invalid titles gracefully
1180 if ( !isset( $this->mAllPages[0][$title] ) ) {
1181 $this->mAllPages[0][$title] = $this->mFakePageId;
1182 $this->mInvalidTitles[$this->mFakePageId] = [
1183 'title' => $title,
1184 'invalidreason' => $this->getErrorFormatter()->formatException( $ex, [ 'bc' => true ] ),
1185 ];
1186 $this->mFakePageId--;
1187 }
1188 continue; // There's nothing else we can do
1189 }
1190 } else {
1191 $titleObj = $title;
1192 }
1193 $unconvertedTitle = $titleObj->getPrefixedText();
1194 $titleWasConverted = false;
1195 if ( $titleObj->isExternal() ) {
1196 // This title is an interwiki link.
1197 $this->mInterwikiTitles[$unconvertedTitle] = $titleObj->getInterwiki();
1198 } else {
1199 // Variants checking
1200 global $wgContLang;
1201 if ( $this->mConvertTitles &&
1202 count( $wgContLang->getVariants() ) > 1 &&
1203 !$titleObj->exists()
1204 ) {
1205 // Language::findVariantLink will modify titleText and titleObj into
1206 // the canonical variant if possible
1207 $titleText = is_string( $title ) ? $title : $titleObj->getPrefixedText();
1208 $wgContLang->findVariantLink( $titleText, $titleObj );
1209 $titleWasConverted = $unconvertedTitle !== $titleObj->getPrefixedText();
1210 }
1211
1212 if ( $titleObj->getNamespace() < 0 ) {
1213 // Handle Special and Media pages
1214 $titleObj = $titleObj->fixSpecialName();
1215 $ns = $titleObj->getNamespace();
1216 $dbkey = $titleObj->getDBkey();
1217 if ( !isset( $this->mAllSpecials[$ns][$dbkey] ) ) {
1218 $this->mAllSpecials[$ns][$dbkey] = $this->mFakePageId;
1219 $target = null;
1220 if ( $ns === NS_SPECIAL && $this->mResolveRedirects ) {
1221 $special = SpecialPageFactory::getPage( $dbkey );
1222 if ( $special instanceof RedirectSpecialArticle ) {
1223 // Only RedirectSpecialArticle is intended to redirect to an article, other kinds of
1224 // RedirectSpecialPage are probably applying weird URL parameters we don't want to
1225 // handle.
1226 $context = new DerivativeContext( $this );
1227 $context->setTitle( $titleObj );
1228 $context->setRequest( new FauxRequest );
1229 $special->setContext( $context );
1230 list( /* $alias */, $subpage ) = SpecialPageFactory::resolveAlias( $dbkey );
1231 $target = $special->getRedirect( $subpage );
1232 }
1233 }
1234 if ( $target ) {
1235 $this->mPendingRedirectSpecialPages[$dbkey] = [ $titleObj, $target ];
1236 } else {
1237 $this->mSpecialTitles[$this->mFakePageId] = $titleObj;
1238 $this->mFakePageId--;
1239 }
1240 }
1241 } else {
1242 // Regular page
1243 $linkBatch->addObj( $titleObj );
1244 }
1245 }
1246
1247 // Make sure we remember the original title that was
1248 // given to us. This way the caller can correlate new
1249 // titles with the originally requested when e.g. the
1250 // namespace is localized or the capitalization is
1251 // different
1252 if ( $titleWasConverted ) {
1253 $this->mConvertedTitles[$unconvertedTitle] = $titleObj->getPrefixedText();
1254 // In this case the page can't be Special.
1255 if ( is_string( $title ) && $title !== $unconvertedTitle ) {
1256 $this->mNormalizedTitles[$title] = $unconvertedTitle;
1257 }
1258 } elseif ( is_string( $title ) && $title !== $titleObj->getPrefixedText() ) {
1259 $this->mNormalizedTitles[$title] = $titleObj->getPrefixedText();
1260 }
1261
1262 // Need gender information
1263 if ( MWNamespace::hasGenderDistinction( $titleObj->getNamespace() ) ) {
1264 $usernames[] = $titleObj->getText();
1265 }
1266 }
1267 // Get gender information
1268 $genderCache = MediaWikiServices::getInstance()->getGenderCache();
1269 $genderCache->doQuery( $usernames, __METHOD__ );
1270
1271 return $linkBatch;
1272 }
1273
1289 public function setGeneratorData( Title $title, array $data ) {
1290 $ns = $title->getNamespace();
1291 $dbkey = $title->getDBkey();
1292 $this->mGeneratorData[$ns][$dbkey] = $data;
1293 }
1294
1314 public function setRedirectMergePolicy( $callable ) {
1315 $this->mRedirectMergePolicy = $callable;
1316 }
1317
1338 public function populateGeneratorData( &$result, array $path = [] ) {
1339 if ( $result instanceof ApiResult ) {
1340 $data = $result->getResultData( $path );
1341 if ( $data === null ) {
1342 return true;
1343 }
1344 } else {
1345 $data = &$result;
1346 foreach ( $path as $key ) {
1347 if ( !isset( $data[$key] ) ) {
1348 // Path isn't in $result, so nothing to add, so everything
1349 // "fits"
1350 return true;
1351 }
1352 $data = &$data[$key];
1353 }
1354 }
1355 foreach ( $this->mGeneratorData as $ns => $dbkeys ) {
1356 if ( $ns === NS_SPECIAL ) {
1357 $pages = [];
1358 foreach ( $this->mSpecialTitles as $id => $title ) {
1359 $pages[$title->getDBkey()] = $id;
1360 }
1361 } else {
1362 if ( !isset( $this->mAllPages[$ns] ) ) {
1363 // No known titles in the whole namespace. Skip it.
1364 continue;
1365 }
1366 $pages = $this->mAllPages[$ns];
1367 }
1368 foreach ( $dbkeys as $dbkey => $genData ) {
1369 if ( !isset( $pages[$dbkey] ) ) {
1370 // Unknown title. Forget it.
1371 continue;
1372 }
1373 $pageId = $pages[$dbkey];
1374 if ( !isset( $data[$pageId] ) ) {
1375 // $pageId didn't make it into the result. Ignore it.
1376 continue;
1377 }
1378
1379 if ( $result instanceof ApiResult ) {
1380 $path2 = array_merge( $path, [ $pageId ] );
1381 foreach ( $genData as $key => $value ) {
1382 if ( !$result->addValue( $path2, $key, $value ) ) {
1383 return false;
1384 }
1385 }
1386 } else {
1387 $data[$pageId] = array_merge( $data[$pageId], $genData );
1388 }
1389 }
1390 }
1391
1392 // Merge data generated about redirect titles into the redirect destination
1393 if ( $this->mRedirectMergePolicy ) {
1394 foreach ( $this->mResolvedRedirectTitles as $titleFrom ) {
1395 $dest = $titleFrom;
1396 while ( isset( $this->mRedirectTitles[$dest->getPrefixedText()] ) ) {
1397 $dest = $this->mRedirectTitles[$dest->getPrefixedText()];
1398 }
1399 $fromNs = $titleFrom->getNamespace();
1400 $fromDBkey = $titleFrom->getDBkey();
1401 $toPageId = $dest->getArticleID();
1402 if ( isset( $data[$toPageId] ) &&
1403 isset( $this->mGeneratorData[$fromNs][$fromDBkey] )
1404 ) {
1405 // It is necesary to set both $data and add to $result, if an ApiResult,
1406 // to ensure multiple redirects to the same destination are all merged.
1407 $data[$toPageId] = call_user_func(
1408 $this->mRedirectMergePolicy,
1409 $data[$toPageId],
1410 $this->mGeneratorData[$fromNs][$fromDBkey]
1411 );
1412 if ( $result instanceof ApiResult ) {
1413 if ( !$result->addValue( $path, $toPageId, $data[$toPageId], ApiResult::OVERRIDE ) ) {
1414 return false;
1415 }
1416 }
1417 }
1418 }
1419 }
1420
1421 return true;
1422 }
1423
1428 protected function getDB() {
1429 return $this->mDbSource->getDB();
1430 }
1431
1438 private static function getPositiveIntegers( $array ) {
1439 // T27734 API: possible issue with revids validation
1440 // It seems with a load of revision rows, MySQL gets upset
1441 // Remove any < 0 integers, as they can't be valid
1442 foreach ( $array as $i => $int ) {
1443 if ( $int < 0 ) {
1444 unset( $array[$i] );
1445 }
1446 }
1447
1448 return $array;
1449 }
1450
1451 public function getAllowedParams( $flags = 0 ) {
1452 $result = [
1453 'titles' => [
1454 ApiBase::PARAM_ISMULTI => true,
1455 ApiBase::PARAM_HELP_MSG => 'api-pageset-param-titles',
1456 ],
1457 'pageids' => [
1458 ApiBase::PARAM_TYPE => 'integer',
1459 ApiBase::PARAM_ISMULTI => true,
1460 ApiBase::PARAM_HELP_MSG => 'api-pageset-param-pageids',
1461 ],
1462 'revids' => [
1463 ApiBase::PARAM_TYPE => 'integer',
1464 ApiBase::PARAM_ISMULTI => true,
1465 ApiBase::PARAM_HELP_MSG => 'api-pageset-param-revids',
1466 ],
1467 'generator' => [
1468 ApiBase::PARAM_TYPE => null,
1469 ApiBase::PARAM_HELP_MSG => 'api-pageset-param-generator',
1471 ],
1472 'redirects' => [
1473 ApiBase::PARAM_DFLT => false,
1474 ApiBase::PARAM_HELP_MSG => $this->mAllowGenerator
1475 ? 'api-pageset-param-redirects-generator'
1476 : 'api-pageset-param-redirects-nogenerator',
1477 ],
1478 'converttitles' => [
1479 ApiBase::PARAM_DFLT => false,
1481 'api-pageset-param-converttitles',
1482 [ Message::listParam( LanguageConverter::$languagesWithVariants, 'text' ) ],
1483 ],
1484 ],
1485 ];
1486
1487 if ( !$this->mAllowGenerator ) {
1488 unset( $result['generator'] );
1489 } elseif ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
1490 $result['generator'][ApiBase::PARAM_TYPE] = 'submodule';
1491 $result['generator'][ApiBase::PARAM_SUBMODULE_MAP] = $this->getGenerators();
1492 }
1493
1494 return $result;
1495 }
1496
1497 protected function handleParamNormalization( $paramName, $value, $rawValue ) {
1498 parent::handleParamNormalization( $paramName, $value, $rawValue );
1499
1500 if ( $paramName === 'titles' ) {
1501 // For the 'titles' parameter, we want to split it like ApiBase would
1502 // and add any changed titles to $this->mNormalizedTitles
1503 $value = $this->explodeMultiValue( $value, self::LIMIT_SML2 + 1 );
1504 $l = count( $value );
1505 $rawValue = $this->explodeMultiValue( $rawValue, $l );
1506 for ( $i = 0; $i < $l; $i++ ) {
1507 if ( $value[$i] !== $rawValue[$i] ) {
1508 $this->mNormalizedTitles[$rawValue[$i]] = $value[$i];
1509 }
1510 }
1511 }
1512 }
1513
1514 private static $generators = null;
1515
1520 private function getGenerators() {
1521 if ( self::$generators === null ) {
1523 if ( !( $query instanceof ApiQuery ) ) {
1524 // If the parent container of this pageset is not ApiQuery,
1525 // we must create it to get module manager
1526 $query = $this->getMain()->getModuleManager()->getModule( 'query' );
1527 }
1528 $gens = [];
1529 $prefix = $query->getModulePath() . '+';
1530 $mgr = $query->getModuleManager();
1531 foreach ( $mgr->getNamesWithClasses() as $name => $class ) {
1532 if ( is_subclass_of( $class, ApiQueryGeneratorBase::class ) ) {
1533 $gens[$name] = $prefix . $name;
1534 }
1535 }
1536 ksort( $gens );
1537 self::$generators = $gens;
1538 }
1539
1540 return self::$generators;
1541 }
1542}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:37
const PARAM_SUBMODULE_MAP
(string[]) When PARAM_TYPE is 'submodule', map parameter values to submodule paths.
Definition ApiBase.php:165
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition ApiBase.php:730
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition ApiBase.php:1895
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition ApiBase.php:2078
getMain()
Get the main module.
Definition ApiBase.php:537
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below.
Definition ApiBase.php:87
getErrorFormatter()
Get the error formatter.
Definition ApiBase.php:655
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
Definition ApiBase.php:48
extractRequestParams( $parseLimit=true)
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:749
const PARAM_SUBMODULE_PARAM_PREFIX
(string) When PARAM_TYPE is 'submodule', used to indicate the 'g' prefix added by ApiQueryGeneratorBa...
Definition ApiBase.php:172
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:124
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1819
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When set, the result could take longer to generate, but should be more thoro...
Definition ApiBase.php:247
explodeMultiValue( $value, $limit)
Split a multi-valued parameter string, like explode()
Definition ApiBase.php:1376
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
Definition ApiBase.php:51
This class contains a list of pages that the client has requested.
getGoodAndMissingTitlesByNamespace()
Returns an array [ns][dbkey] => page_id for all good and missing titles.
initFromPageIds( $pageids)
Does the same as initFromTitles(), but is based on page IDs instead.
populateFromRevisionIDs( $revIDs)
Populate this PageSet from a list of revision IDs.
getInterwikiTitlesAsResult( $result=null, $iwUrl=false)
Get a list of interwiki titles - maps a title to its interwiki prefix as result.
getCustomField( $fieldName)
Get the value of a custom field previously requested through requestField()
getNormalizedTitles()
Get a list of title normalizations - maps a title to its normalized version.
getGenerators()
Get an array of all available generators.
__construct(ApiBase $dbSource, $flags=0, $defaultNamespace=NS_MAIN)
getGoodTitlesByNamespace()
Returns an array [ns][dbkey] => page_id for all good titles.
getAllowedParams( $flags=0)
getRevisionIDs()
Get the list of valid revision IDs (requested with the revids= parameter)
getGoodAndMissingTitles()
Title objects for good and missing titles.
populateFromPageIDs( $pageIDs)
Populate this PageSet from a list of page IDs.
getRedirectTargets()
Get the targets of the pending redirects from the database.
getMissingTitlesByNamespace()
Returns an array [ns][dbkey] => fake_page_id for all missing titles.
static getPositiveIntegers( $array)
Returns the input array of integers with all values < 0 removed.
getMissingTitles()
Title objects that were NOT found in the database.
getDB()
Get the database connection (read-only)
static $generators
initFromRevIDs( $revids)
Does the same as initFromTitles(), but is based on revision IDs instead.
executeDryRun()
In case execute() is not called, call this method to mark all relevant parameters as used This preven...
getRedirectTitlesAsResult( $result=null)
Get a list of redirect resolutions - maps a title to its redirect target.
getPageTableFields()
Get the fields that have to be queried from the page table: the ones requested through requestField()...
getGoodTitleCount()
Returns the number of found unique pages (not revisions) in the set.
getRevisionCount()
Returns the number of revisions (requested with revids= parameter).
getAllTitlesByNamespace()
Returns an array [ns][dbkey] => page_id for all requested titles.
processDbRow( $row)
Extract all requested fields from the row received from the database.
processTitlesArray( $titles)
Given an array of title strings, convert them into Title objects.
static addValues(array &$result, $values, $flags=[], $name=null)
Add all items from $values into the result.
setRedirectMergePolicy( $callable)
Controls how generator data about a redirect source is merged into the generator data for the redirec...
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
getNormalizedTitlesAsResult( $result=null)
Get a list of title normalizations - maps a title to its normalized version in the form of result arr...
getTitleCount()
Returns the number of unique pages (not revisions) in the set.
initFromTitles( $titles)
This method populates internal variables with page information based on the given array of title stri...
getInvalidTitlesAndReasons()
Titles that were deemed invalid by Title::newFromText() The array's index will be unique and negative...
array $mInvalidTitles
[fake_page_id] => [ 'title' => $title, 'invalidreason' => $reason ]
getSpecialTitles()
Get the list of titles with negative namespace.
Title[] $mPendingRedirectIDs
getTitles()
All Title objects provided.
int $mDefaultNamespace
executeInternal( $isDryRun)
Populate the PageSet from the request parameters.
resolvePendingRedirects()
Resolve any redirects in the result if redirect resolution was requested.
populateFromQueryResult( $db, $queryResult)
Populate this PageSet from a rowset returned from the database.
getMissingPageIDs()
Page IDs that were not found in the database.
requestField( $fieldName)
Request an additional field from the page table.
getInterwikiTitles()
Get a list of interwiki titles - maps a title to its interwiki prefix.
populateFromTitles( $titles)
Populate this PageSet from a list of Titles.
getMissingRevisionIDs()
Revision IDs that were not found in the database.
execute()
Populate the PageSet from the request parameters.
populateGeneratorData(&$result, array $path=[])
Populate the generator data for all titles in the result.
$mPendingRedirectSpecialPages
getConvertedTitlesAsResult( $result=null)
Get a list of title conversions - maps a title to its converted version as a result array.
getConvertedTitles()
Get a list of title conversions - maps a title to its converted version.
getInvalidTitles()
Titles that were deemed invalid by Title::newFromText() The array's index will be unique and negative...
getDataSource()
Return the parameter name that is the source of data for this PageSet.
getInvalidTitlesAndRevisions( $invalidChecks=[ 'invalidTitles', 'special', 'missingIds', 'missingRevIds', 'missingTitles', 'interwikiTitles'])
Get an array of invalid/special/missing titles.
getLiveRevisionIDs()
Get the list of non-deleted revision IDs (requested with the revids= parameter)
getCacheMode( $params=null)
Get the cache mode for the data generated by this module.
getGoodTitles()
Title objects that were found in the database.
$mResolvedRedirectTitles
callable null $mRedirectMergePolicy
isResolvingRedirects()
Check whether this PageSet is resolving redirects.
getRedirectTitles()
Get a list of redirect resolutions - maps a title to its redirect target, as an array of output-ready...
setGeneratorData(Title $title, array $data)
Set data for a title.
const DISABLE_GENERATORS
Constructor flag: The new instance of ApiPageSet will ignore the 'generator=' parameter.
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...
getMissingRevisionIDsAsResult( $result=null)
Revision IDs that were not found in the database as result array.
getDeletedRevisionIDs()
Get the list of revision IDs that were associated with deleted titles.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
This is the main query class.
Definition ApiQuery.php:36
This class represents the result of the API operations.
Definition ApiResult.php:33
const OVERRIDE
Override existing value in addValue(), setValue(), and similar functions.
Definition ApiResult.php:39
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
IContextSource $context
An IContextSource implementation which will inherit context from another source but allow individual ...
WebRequest clone which takes values from a provided array.
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition LinkBatch.php:34
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Superclass for any RedirectSpecialPage which redirects the user to a particular article (as opposed t...
static getPage( $name)
Find the object with a given name and return it (or NULL)
static resolveAlias( $alias)
Given a special page name with a possible subpage, return an array where the first element is the spe...
Represents a title within MediaWiki.
Definition Title.php:39
Result wrapper for grabbing data queried from an IDatabase object.
$res
Definition database.txt:21
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
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 local content language as $wgContLang
Definition design.txt:57
namespace being checked & $result
Definition hooks.txt:2323
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:1015
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:964
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
null for the local 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:1620
const PROTO_CURRENT
Definition Defines.php:232
const NS_MAIN
Definition Defines.php:74
const NS_SPECIAL
Definition Defines.php:63
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:38
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
$params