Merge "MimeAnalyzer: Add testcases for mp3 detection"
[lhc/web/wiklou.git] / includes / api / ApiPageSet.php
index 85c6860..cfac761 100644 (file)
@@ -71,6 +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 = [];
@@ -120,7 +121,7 @@ class ApiPageSet extends ApiBase {
        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();
@@ -165,7 +166,7 @@ class ApiPageSet extends ApiBase {
                        }
                        // 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() );
 
@@ -813,6 +814,8 @@ class ApiPageSet extends ApiBase {
                // Get validated and normalized title objects
                $linkBatch = $this->processTitlesArray( $titles );
                if ( $linkBatch->isEmpty() ) {
+                       // There might be special-page redirects
+                       $this->resolvePendingRedirects();
                        return;
                }
 
@@ -1033,7 +1036,7 @@ class ApiPageSet extends ApiBase {
 
                        // 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();
@@ -1067,56 +1070,76 @@ class ApiPageSet extends ApiBase {
                $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 );
@@ -1197,8 +1220,26 @@ class ApiPageSet extends ApiBase {
                                        $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
@@ -1315,7 +1356,7 @@ class ApiPageSet extends ApiBase {
                        }
                }
                foreach ( $this->mGeneratorData as $ns => $dbkeys ) {
-                       if ( $ns === -1 ) {
+                       if ( $ns === NS_SPECIAL ) {
                                $pages = [];
                                foreach ( $this->mSpecialTitles as $id => $title ) {
                                        $pages[$title->getDBkey()] = $id;
@@ -1385,7 +1426,7 @@ class ApiPageSet extends ApiBase {
 
        /**
         * Get the database connection (read-only)
-        * @return Database
+        * @return IDatabase
         */
        protected function getDB() {
                return $this->mDbSource->getDB();