Merge "ApiPageSet: Follow RedirectSpecialArticle redirects"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sat, 8 Apr 2017 09:36:21 +0000 (09:36 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sat, 8 Apr 2017 09:36:21 +0000 (09:36 +0000)
1  2 
includes/api/ApiPageSet.php

@@@ -25,7 -25,6 +25,7 @@@
   */
  use MediaWiki\MediaWikiServices;
  use Wikimedia\Rdbms\ResultWrapper;
 +use Wikimedia\Rdbms\IDatabase;
  
  /**
   * This class contains a list of pages that the client has requested.
@@@ -71,6 -70,7 +71,7 @@@ class ApiPageSet extends ApiBase 
        private $mInterwikiTitles = [];
        /** @var Title[] */
        private $mPendingRedirectIDs = [];
+       private $mPendingRedirectSpecialPages = []; // [dbkey] => [ Title $from, Title $to ]
        private $mResolvedRedirectTitles = [];
        private $mConvertedTitles = [];
        private $mGoodRevIDs = [];
                // 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