96 private static function addValues( array &$result, $values, $flags = [], $name =
null ) {
97 foreach ( $values as $val ) {
98 if ( $val instanceof
Title ) {
101 } elseif ( $name !==
null ) {
102 $v = [ $name => $val ];
106 foreach ( $flags as $flag ) {
122 $this->mDbSource = $dbSource;
124 $this->mDefaultNamespace = $defaultNamespace;
127 $this->mResolveRedirects = $this->mParams[
'redirects'];
128 $this->mConvertTitles = $this->mParams[
'converttitles'];
152 $generatorName = $this->mAllowGenerator ? $this->mParams[
'generator'] :
null;
153 if ( isset( $generatorName ) ) {
155 if ( !$dbSource instanceof
ApiQuery ) {
157 $dbSource = $this->
getMain()->getModuleManager()->getModule(
'query' );
159 $generator = $dbSource->getModuleManager()->getModule( $generatorName,
null,
true );
161 $this->
dieWithError( [
'apierror-badgenerator-unknown', $generatorName ],
'badgenerator' );
164 $this->
dieWithError( [
'apierror-badgenerator-notgenerator', $generatorName ],
'badgenerator' );
168 $tmpPageSet =
new ApiPageSet( $dbSource, self::DISABLE_GENERATORS );
175 $tmpPageSet->executeInternal( $isDryRun );
185 foreach (
$generator->extractRequestParams() as $paramName => $param ) {
186 $main->markParamsUsed(
$generator->encodeParamName( $paramName ) );
196 if ( isset( $this->mParams[
'titles'] ) ) {
197 $dataSource =
'titles';
199 if ( isset( $this->mParams[
'pageids'] ) ) {
200 if ( isset( $dataSource ) ) {
203 'apierror-invalidparammix-cannotusewith',
210 $dataSource =
'pageids';
212 if ( isset( $this->mParams[
'revids'] ) ) {
213 if ( isset( $dataSource ) ) {
216 'apierror-invalidparammix-cannotusewith',
223 $dataSource =
'revids';
228 switch ( $dataSource ) {
236 if ( $this->mResolveRedirects ) {
237 $this->
addWarning(
'apiwarn-redirectsandrevids' );
239 $this->mResolveRedirects =
false;
267 if ( $this->mAllowGenerator && isset( $this->mParams[
'generator'] ) ) {
270 if ( isset( $this->mParams[
'titles'] ) ) {
273 if ( isset( $this->mParams[
'pageids'] ) ) {
276 if ( isset( $this->mParams[
'revids'] ) ) {
289 $this->mRequestedPageFields[$fieldName] =
null;
299 return $this->mRequestedPageFields[$fieldName];
312 'page_namespace' =>
null,
313 'page_title' =>
null,
317 if ( $this->mResolveRedirects ) {
318 $pageFlds[
'page_is_redirect'] =
null;
321 $pageFlds[
'page_content_model'] =
null;
323 if ( $this->
getConfig()->
get(
'PageLanguageUseDB' ) ) {
324 $pageFlds[
'page_lang'] =
null;
328 $pageFlds[$field] =
null;
331 $pageFlds = array_merge( $pageFlds, $this->mRequestedPageFields );
333 return array_keys( $pageFlds );
359 return count( $this->mTitles );
383 return count( $this->mGoodTitles );
457 'from' => strval( $titleStrFrom ),
458 'to' => $titleTo->getPrefixedText(),
460 if ( $titleTo->hasFragment() ) {
461 $r[
'tofragment'] = $titleTo->getFragment();
463 if ( $titleTo->isExternal() ) {
464 $r[
'tointerwiki'] = $titleTo->getInterwiki();
466 if ( isset( $this->mResolvedRedirectTitles[$titleStrFrom] ) ) {
467 $titleFrom = $this->mResolvedRedirectTitles[$titleStrFrom];
468 $ns = $titleFrom->getNamespace();
469 $dbkey = $titleFrom->getDBkey();
470 if ( isset( $this->mGeneratorData[$ns][$dbkey] ) ) {
471 $r = array_merge( $this->mGeneratorData[$ns][$dbkey], $r );
477 if ( !empty( $values ) && $result ) {
502 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
504 $encode = $contLang->normalize( $rawTitleStr ) !== $rawTitleStr;
506 'fromencoded' => $encode,
507 'from' => $encode ? rawurlencode( $rawTitleStr ) : $rawTitleStr,
511 if ( !empty( $values ) && $result ) {
538 'from' => $rawTitleStr,
542 if ( !empty( $values ) && $result ) {
570 'title' => $rawTitleStr,
571 'iw' => $interwikiStr,
579 if ( !empty( $values ) && $result ) {
601 'special',
'missingIds',
'missingRevIds',
'missingTitles',
'interwikiTitles' ]
604 if ( in_array(
'invalidTitles', $invalidChecks ) ) {
607 if ( in_array(
'special', $invalidChecks ) ) {
611 if (
$title->isKnown() ) {
620 if ( in_array(
'missingIds', $invalidChecks ) ) {
623 if ( in_array(
'missingRevIds', $invalidChecks ) ) {
626 if ( in_array(
'missingTitles', $invalidChecks ) ) {
630 if (
$title->isKnown() ) {
639 if ( in_array(
'interwikiTitles', $invalidChecks ) ) {
691 if ( !empty( $values ) && $result ) {
759 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
760 $linkCache->addGoodLinkObjFromRow(
$title, $row );
762 $pageId = (int)$row->page_id;
763 $this->mAllPages[$row->page_namespace][$row->page_title] = $pageId;
764 $this->mTitles[] =
$title;
766 if ( $this->mResolveRedirects && $row->page_is_redirect ==
'1' ) {
767 $this->mPendingRedirectIDs[$pageId] =
$title;
769 $this->mGoodPages[$row->page_namespace][$row->page_title] = $pageId;
770 $this->mGoodAndMissingPages[$row->page_namespace][$row->page_title] = $pageId;
771 $this->mGoodTitles[$pageId] =
$title;
774 foreach ( $this->mRequestedPageFields as $fieldName => &$fieldValues ) {
775 $fieldValues[$pageId] = $row->$fieldName;
798 if ( $linkBatch->isEmpty() ) {
804 $db = $this->
getDB();
805 $set = $linkBatch->constructSet(
'page', $db );
828 $pageids = array_map(
'intval', $pageids );
829 $remaining = array_flip( $pageids );
832 $pageids = $this->
filterIDs( [ [
'page',
'page_id' ] ], $pageids );
836 if ( !empty( $pageids ) ) {
838 'page_id' => $pageids
840 $db = $this->
getDB();
864 if ( $remaining !==
null && $processTitles ===
null ) {
865 ApiBase::dieDebug( __METHOD__,
'Missing $processTitles parameter when $remaining is provided' );
868 $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
872 foreach (
$res as $row ) {
873 $pageId = (int)$row->page_id;
876 if ( isset( $remaining ) ) {
877 if ( $processTitles ) {
878 unset( $remaining[$row->page_namespace][$row->page_title] );
880 unset( $remaining[$pageId] );
888 if ( $nsInfo->hasGenderDistinction( $row->page_namespace ) ) {
889 $usernames[] = $row->page_title;
894 if ( isset( $remaining ) ) {
896 if ( $processTitles ) {
898 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
899 foreach ( $remaining as $ns => $dbkeys ) {
900 foreach ( array_keys( $dbkeys ) as $dbkey ) {
902 $linkCache->addBadLinkObj(
$title );
907 $this->mFakePageId--;
908 $this->mTitles[] =
$title;
911 if ( $nsInfo->hasGenderDistinction( $ns ) ) {
912 $usernames[] = $dbkey;
918 if ( !$this->mMissingPageIDs ) {
919 $this->mMissingPageIDs = array_keys( $remaining );
921 $this->mMissingPageIDs = array_merge( $this->mMissingPageIDs, array_keys( $remaining ) );
927 $genderCache = MediaWikiServices::getInstance()->getGenderCache();
928 $genderCache->doQuery( $usernames, __METHOD__ );
941 $revids = array_map(
'intval', $revids );
942 $db = $this->
getDB();
944 $remaining = array_flip( $revids );
946 $revids = $this->
filterIDs( [ [
'revision',
'rev_id' ], [
'archive',
'ar_rev_id' ] ], $revids );
947 $goodRemaining = array_flip( $revids );
950 $tables = [
'revision',
'page' ];
951 $fields = [
'rev_id',
'rev_page' ];
952 $where = [
'rev_id' => $revids,
'rev_page = page_id' ];
955 $res = $db->select( $tables, $fields, $where, __METHOD__ );
956 foreach (
$res as $row ) {
957 $revid = (int)$row->rev_id;
958 $pageid = (
int)$row->rev_page;
959 $this->mGoodRevIDs[$revid] = $pageid;
960 $this->mLiveRevIDs[$revid] = $pageid;
961 $pageids[$pageid] =
'';
962 unset( $remaining[$revid] );
963 unset( $goodRemaining[$revid] );
973 if ( $goodRemaining &&
975 $tables = [
'archive' ];
976 $fields = [
'ar_rev_id',
'ar_namespace',
'ar_title' ];
977 $where = [
'ar_rev_id' => array_keys( $goodRemaining ) ];
979 $res = $db->select( $tables, $fields, $where, __METHOD__ );
981 foreach (
$res as $row ) {
982 $revid = (int)$row->ar_rev_id;
984 unset( $remaining[$revid] );
989 foreach ( $titles as $revid =>
$title ) {
990 $ns =
$title->getNamespace();
991 $dbkey =
$title->getDBkey();
994 if ( !isset( $this->mAllPages[$ns][$dbkey] ) &&
995 isset( $this->mConvertedTitles[
$title->getPrefixedText()] )
998 $ns =
$title->getNamespace();
999 $dbkey =
$title->getDBkey();
1002 if ( isset( $this->mAllPages[$ns][$dbkey] ) ) {
1003 $this->mGoodRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
1004 $this->mDeletedRevIDs[$revid] = $this->mAllPages[$ns][$dbkey];
1006 $remaining[$revid] =
true;
1011 $this->mMissingRevIDs = array_keys( $remaining );
1020 if ( $this->mResolveRedirects ) {
1021 $db = $this->
getDB();
1026 while ( $this->mPendingRedirectIDs || $this->mPendingRedirectSpecialPages ) {
1031 if ( $linkBatch->isEmpty() ) {
1035 $set = $linkBatch->constructSet(
'page', $db );
1036 if ( $set ===
false ) {
1041 $res = $db->select(
'page', $pageFlds, $set, __METHOD__ );
1057 $titlesToResolve = [];
1058 $db = $this->
getDB();
1060 if ( $this->mPendingRedirectIDs ) {
1069 ], [
'rd_from' => array_keys( $this->mPendingRedirectIDs ) ],
1072 foreach (
$res as $row ) {
1073 $rdfrom = (int)$row->rd_from;
1074 $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
1081 $this->mResolvedRedirectTitles[$from] = $this->mPendingRedirectIDs[$rdfrom];
1082 unset( $this->mPendingRedirectIDs[$rdfrom] );
1083 if ( $to->isExternal() ) {
1084 $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
1085 } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
1086 $titlesToResolve[] = $to;
1088 $this->mRedirectTitles[$from] = $to;
1091 if ( $this->mPendingRedirectIDs ) {
1094 foreach ( $this->mPendingRedirectIDs as $id =>
$title ) {
1096 $rt = $page->insertRedirect();
1101 if ( $rt->isExternal() ) {
1102 $this->mInterwikiTitles[$rt->getPrefixedText()] = $rt->getInterwiki();
1103 } elseif ( !isset( $this->mAllPages[$rt->getNamespace()][$rt->getDBkey()] ) ) {
1104 $titlesToResolve[] = $rt;
1106 $from =
$title->getPrefixedText();
1107 $this->mResolvedRedirectTitles[$from] =
$title;
1108 $this->mRedirectTitles[$from] = $rt;
1109 unset( $this->mPendingRedirectIDs[$id] );
1114 if ( $this->mPendingRedirectSpecialPages ) {
1115 foreach ( $this->mPendingRedirectSpecialPages as $key => list( $from, $to ) ) {
1117 $fromKey = $from->getPrefixedText();
1118 $this->mResolvedRedirectTitles[$fromKey] = $from;
1119 $this->mRedirectTitles[$fromKey] = $to;
1120 if ( $to->isExternal() ) {
1121 $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
1122 } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
1123 $titlesToResolve[] = $to;
1126 $this->mPendingRedirectSpecialPages = [];
1130 $this->mCacheMode =
'private';
1163 $services = MediaWikiServices::getInstance();
1164 $linkBatchFactory = $services->getLinkBatchFactory();
1165 $linkBatch = $linkBatchFactory->newLinkBatch();
1166 $languageConverter = $services
1167 ->getLanguageConverterFactory()
1168 ->getLanguageConverter( $services->getContentLanguage() );
1171 foreach ( $titles as $index =>
$title ) {
1172 if ( is_string(
$title ) ) {
1178 if ( !isset( $this->mAllPages[0][
$title] ) ) {
1182 'invalidreason' => $this->
getErrorFormatter()->formatException( $ex, [
'bc' =>
true ] ),
1184 $this->mFakePageId--;
1192 $titleObjects[$index] = $titleObj;
1196 $genderCache = $services->getGenderCache();
1197 $genderCache->doTitlesArray( $titleObjects, __METHOD__ );
1199 foreach ( $titleObjects as $index => $titleObj ) {
1200 $title = is_string( $titles[$index] ) ? $titles[$index] :
false;
1201 $unconvertedTitle = $titleObj->getPrefixedText();
1202 $titleWasConverted =
false;
1203 if ( $titleObj->isExternal() ) {
1205 $this->mInterwikiTitles[$unconvertedTitle] = $titleObj->getInterwiki();
1209 $this->mConvertTitles
1210 && $languageConverter->hasVariants()
1211 && !$titleObj->exists()
1215 $titleText =
$title !==
false ?
$title : $titleObj->getPrefixedText();
1216 $languageConverter->findVariantLink( $titleText, $titleObj );
1217 $titleWasConverted = $unconvertedTitle !== $titleObj->getPrefixedText();
1220 if ( $titleObj->getNamespace() < 0 ) {
1222 $titleObj = $titleObj->fixSpecialName();
1223 $ns = $titleObj->getNamespace();
1224 $dbkey = $titleObj->getDBkey();
1225 if ( !isset( $this->mAllSpecials[$ns][$dbkey] ) ) {
1228 if ( $ns ===
NS_SPECIAL && $this->mResolveRedirects ) {
1229 $spFactory = $services->getSpecialPageFactory();
1230 $special = $spFactory->getPage( $dbkey );
1239 list( , $subpage ) = $spFactory->resolveAlias( $dbkey );
1240 $target = $special->getRedirect( $subpage );
1244 $this->mPendingRedirectSpecialPages[$dbkey] = [ $titleObj, $target ];
1247 $this->mFakePageId--;
1252 $linkBatch->addObj( $titleObj );
1261 if ( $titleWasConverted ) {
1262 $this->mConvertedTitles[$unconvertedTitle] = $titleObj->getPrefixedText();
1264 if (
$title !==
false &&
$title !== $unconvertedTitle ) {
1265 $this->mNormalizedTitles[
$title] = $unconvertedTitle;
1267 } elseif (
$title !==
false &&
$title !== $titleObj->getPrefixedText() ) {
1268 $this->mNormalizedTitles[
$title] = $titleObj->getPrefixedText();
1291 $ns =
$title->getNamespace();
1292 $dbkey =
$title->getDBkey();
1293 $this->mGeneratorData[$ns][$dbkey] = $data;
1316 $this->mRedirectMergePolicy = $callable;
1333 while ( isset( $this->mRedirectTitles[$dest->getPrefixedText()] ) ) {
1334 $dest = $this->mRedirectTitles[$dest->getPrefixedText()];
1335 if ( isset( $seen[$dest->getPrefixedText()] ) ) {
1338 $seen[$dest->getPrefixedText()] =
true;
1365 $data = $result->getResultData(
$path );
1366 if ( $data ===
null ) {
1371 foreach (
$path as $key ) {
1372 if ( !isset( $data[$key] ) ) {
1377 $data = &$data[$key];
1380 foreach ( $this->mGeneratorData as $ns => $dbkeys ) {
1383 foreach ( $this->mSpecialTitles as $id =>
$title ) {
1384 $pages[
$title->getDBkey()] = $id;
1387 if ( !isset( $this->mAllPages[$ns] ) ) {
1391 $pages = $this->mAllPages[$ns];
1393 foreach ( $dbkeys as $dbkey => $genData ) {
1394 if ( !isset( $pages[$dbkey] ) ) {
1398 $pageId = $pages[$dbkey];
1399 if ( !isset( $data[$pageId] ) ) {
1405 $path2 = array_merge(
$path, [ $pageId ] );
1406 foreach ( $genData as $key => $value ) {
1407 if ( !$result->addValue( $path2, $key, $value ) ) {
1412 $data[$pageId] = array_merge( $data[$pageId], $genData );
1418 if ( $this->mRedirectMergePolicy ) {
1419 foreach ( $this->mResolvedRedirectTitles as $titleFrom ) {
1421 $fromNs = $titleFrom->getNamespace();
1422 $fromDBkey = $titleFrom->getDBkey();
1423 $toPageId = $dest->getArticleID();
1424 if ( isset( $data[$toPageId] ) &&
1425 isset( $this->mGeneratorData[$fromNs][$fromDBkey] )
1429 $data[$toPageId] = call_user_func(
1430 $this->mRedirectMergePolicy,
1432 $this->mGeneratorData[$fromNs][$fromDBkey]
1451 return $this->mDbSource->getDB();
1478 ?
'api-pageset-param-redirects-generator'
1479 :
'api-pageset-param-redirects-nogenerator',
1481 'converttitles' => [
1484 'api-pageset-param-converttitles',
1490 if ( !$this->mAllowGenerator ) {
1491 unset( $result[
'generator'] );
1501 parent::handleParamNormalization( $paramName, $value, $rawValue );
1503 if ( $paramName ===
'titles' ) {
1506 $value = ParamValidator::explodeMultiValue( $value, self::LIMIT_SML2 + 1 );
1507 $l = count( $value );
1508 $rawValue = ParamValidator::explodeMultiValue( $rawValue, $l );
1509 for ( $i = 0; $i < $l; $i++ ) {
1510 if ( $value[$i] !== $rawValue[$i] ) {
1511 $this->mNormalizedTitles[$rawValue[$i]] = $value[$i];
1524 if ( self::$generators ===
null ) {
1526 if ( !( $query instanceof
ApiQuery ) ) {
1529 $query = $this->
getMain()->getModuleManager()->getModule(
'query' );
1532 $prefix = $query->getModulePath() .
'+';
1533 $mgr = $query->getModuleManager();
1534 foreach ( $mgr->getNamesWithClasses() as $name => $class ) {
1535 if ( is_subclass_of( $class, ApiQueryGeneratorBase::class ) ) {
1536 $gens[$name] = $prefix . $name;
1540 self::$generators = $gens;