private $mInterwikiTitles = [];
/** @var Title[] */
private $mPendingRedirectIDs = [];
+ private $mPendingRedirectSpecialPages = []; // [dbkey] => [ Title $from, Title $to ]
private $mResolvedRedirectTitles = [];
private $mConvertedTitles = [];
private $mGoodRevIDs = [];
public function __construct( ApiBase $dbSource, $flags = 0, $defaultNamespace = NS_MAIN ) {
parent::__construct( $dbSource->getMain(), $dbSource->getModuleName() );
$this->mDbSource = $dbSource;
- $this->mAllowGenerator = ( $flags & ApiPageSet::DISABLE_GENERATORS ) == 0;
+ $this->mAllowGenerator = ( $flags & self::DISABLE_GENERATORS ) == 0;
$this->mDefaultNamespace = $defaultNamespace;
$this->mParams = $this->extractRequestParams();
}
// Create a temporary pageset to store generator's output,
// add any additional fields generator may need, and execute pageset to populate titles/pageids
- $tmpPageSet = new ApiPageSet( $dbSource, ApiPageSet::DISABLE_GENERATORS );
+ $tmpPageSet = new ApiPageSet( $dbSource, self::DISABLE_GENERATORS );
$generator->setGeneratorMode( $tmpPageSet );
$this->mCacheMode = $generator->getCacheMode( $generator->extractRequestParams() );
// Get validated and normalized title objects
$linkBatch = $this->processTitlesArray( $titles );
if ( $linkBatch->isEmpty() ) {
+ // There might be special-page redirects
+ $this->resolvePendingRedirects();
return;
}
// Repeat until all redirects have been resolved
// The infinite loop is prevented by keeping all known pages in $this->mAllPages
- while ( $this->mPendingRedirectIDs ) {
+ while ( $this->mPendingRedirectIDs || $this->mPendingRedirectSpecialPages ) {
// Resolve redirects by querying the pagelinks table, and repeat the process
// Create a new linkBatch object for the next pass
$linkBatch = $this->getRedirectTargets();
$titlesToResolve = [];
$db = $this->getDB();
- $res = $db->select(
- 'redirect',
- [
- 'rd_from',
- 'rd_namespace',
- 'rd_fragment',
- 'rd_interwiki',
- 'rd_title'
- ], [ 'rd_from' => array_keys( $this->mPendingRedirectIDs ) ],
- __METHOD__
- );
- foreach ( $res as $row ) {
- $rdfrom = intval( $row->rd_from );
- $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
- $to = Title::makeTitle(
- $row->rd_namespace,
- $row->rd_title,
- $row->rd_fragment,
- $row->rd_interwiki
- );
- $this->mResolvedRedirectTitles[$from] = $this->mPendingRedirectIDs[$rdfrom];
- unset( $this->mPendingRedirectIDs[$rdfrom] );
- if ( $to->isExternal() ) {
- $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
- } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
- $titlesToResolve[] = $to;
+ if ( $this->mPendingRedirectIDs ) {
+ $res = $db->select(
+ 'redirect',
+ [
+ 'rd_from',
+ 'rd_namespace',
+ 'rd_fragment',
+ 'rd_interwiki',
+ 'rd_title'
+ ], [ 'rd_from' => array_keys( $this->mPendingRedirectIDs ) ],
+ __METHOD__
+ );
+ foreach ( $res as $row ) {
+ $rdfrom = intval( $row->rd_from );
+ $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
+ $to = Title::makeTitle(
+ $row->rd_namespace,
+ $row->rd_title,
+ $row->rd_fragment,
+ $row->rd_interwiki
+ );
+ $this->mResolvedRedirectTitles[$from] = $this->mPendingRedirectIDs[$rdfrom];
+ unset( $this->mPendingRedirectIDs[$rdfrom] );
+ if ( $to->isExternal() ) {
+ $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
+ } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
+ $titlesToResolve[] = $to;
+ }
+ $this->mRedirectTitles[$from] = $to;
}
- $this->mRedirectTitles[$from] = $to;
- }
- if ( $this->mPendingRedirectIDs ) {
- // We found pages that aren't in the redirect table
- // Add them
- foreach ( $this->mPendingRedirectIDs as $id => $title ) {
- $page = WikiPage::factory( $title );
- $rt = $page->insertRedirect();
- if ( !$rt ) {
- // What the hell. Let's just ignore this
- continue;
+ if ( $this->mPendingRedirectIDs ) {
+ // We found pages that aren't in the redirect table
+ // Add them
+ foreach ( $this->mPendingRedirectIDs as $id => $title ) {
+ $page = WikiPage::factory( $title );
+ $rt = $page->insertRedirect();
+ if ( !$rt ) {
+ // What the hell. Let's just ignore this
+ continue;
+ }
+ if ( $rt->isExternal() ) {
+ $this->mInterwikiTitles[$rt->getPrefixedText()] = $rt->getInterwiki();
+ } elseif ( !isset( $this->mAllPages[$rt->getNamespace()][$rt->getDBkey()] ) ) {
+ $titlesToResolve[] = $rt;
+ }
+ $from = $title->getPrefixedText();
+ $this->mResolvedRedirectTitles[$from] = $title;
+ $this->mRedirectTitles[$from] = $rt;
+ unset( $this->mPendingRedirectIDs[$id] );
}
- if ( $rt->isExternal() ) {
- $this->mInterwikiTitles[$rt->getPrefixedText()] = $rt->getInterwiki();
- } elseif ( !isset( $this->mAllPages[$rt->getNamespace()][$rt->getDBkey()] ) ) {
- $titlesToResolve[] = $rt;
+ }
+ }
+
+ if ( $this->mPendingRedirectSpecialPages ) {
+ foreach ( $this->mPendingRedirectSpecialPages as $key => list( $from, $to ) ) {
+ $fromKey = $from->getPrefixedText();
+ $this->mResolvedRedirectTitles[$fromKey] = $from;
+ $this->mRedirectTitles[$fromKey] = $to;
+ if ( $to->isExternal() ) {
+ $this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
+ } elseif ( !isset( $this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
+ $titlesToResolve[] = $to;
}
- $from = $title->getPrefixedText();
- $this->mResolvedRedirectTitles[$from] = $title;
- $this->mRedirectTitles[$from] = $rt;
- unset( $this->mPendingRedirectIDs[$id] );
}
+ $this->mPendingRedirectSpecialPages = [];
+
+ // Set private caching since we don't know what criteria the
+ // special pages used to decide on these redirects.
+ $this->mCacheMode = 'private';
}
return $this->processTitlesArray( $titlesToResolve );
$dbkey = $titleObj->getDBkey();
if ( !isset( $this->mAllSpecials[$ns][$dbkey] ) ) {
$this->mAllSpecials[$ns][$dbkey] = $this->mFakePageId;
- $this->mSpecialTitles[$this->mFakePageId] = $titleObj;
- $this->mFakePageId--;
+ $target = null;
+ if ( $ns === NS_SPECIAL && $this->mResolveRedirects ) {
+ $special = SpecialPageFactory::getPage( $dbkey );
+ if ( $special instanceof RedirectSpecialArticle ) {
+ // Only RedirectSpecialArticle is intended to redirect to an article, other kinds of
+ // RedirectSpecialPage are probably applying weird URL parameters we don't want to handle.
+ $context = new DerivativeContext( $this );
+ $context->setTitle( $titleObj );
+ $context->setRequest( new FauxRequest );
+ $special->setContext( $context );
+ list( /* $alias */, $subpage ) = SpecialPageFactory::resolveAlias( $dbkey );
+ $target = $special->getRedirect( $subpage );
+ }
+ }
+ if ( $target ) {
+ $this->mPendingRedirectSpecialPages[$dbkey] = [ $titleObj, $target ];
+ } else {
+ $this->mSpecialTitles[$this->mFakePageId] = $titleObj;
+ $this->mFakePageId--;
+ }
}
} else {
// Regular page
}
}
foreach ( $this->mGeneratorData as $ns => $dbkeys ) {
- if ( $ns === -1 ) {
+ if ( $ns === NS_SPECIAL ) {
$pages = [];
foreach ( $this->mSpecialTitles as $id => $title ) {
$pages[$title->getDBkey()] = $id;
/**
* Get the database connection (read-only)
- * @return Database
+ * @return IDatabase
*/
protected function getDB() {
return $this->mDbSource->getDB();