Merge "Revert "Adding sanity check to Title::isRedirect().""
[lhc/web/wiklou.git] / includes / api / ApiPageSet.php
index 2eafbb3..598f9ad 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * API for MediaWiki 1.8+
+ *
  *
  * Created on Sep 24, 2006
  *
  * @file
  */
 
-if ( !defined( 'MEDIAWIKI' ) ) {
-       // Eclipse helper - will be ignored in production
-       require_once( 'ApiQueryBase.php' );
-}
-
 /**
  * This class contains a list of pages that the client has requested.
  * Initially, when the client passes in titles=, pageids=, or revisions=
@@ -57,8 +52,9 @@ class ApiPageSet extends ApiQueryBase {
 
        /**
         * Constructor
-        * @param $query ApiQuery
+        * @param $query ApiQueryBase
         * @param $resolveRedirects bool Whether redirects should be resolved
+        * @param $convertTitles bool
         */
        public function __construct( $query, $resolveRedirects = false, $convertTitles = false ) {
                parent::__construct( $query, 'query' );
@@ -212,7 +208,7 @@ class ApiPageSet extends ApiQueryBase {
        /**
         * Get a list of redirect resolutions - maps a title to its redirect
         * target.
-        * @return array prefixed_title (string) => prefixed_title (string)
+        * @return array prefixed_title (string) => Title object
         */
        public function getRedirectTitles() {
                return $this->mRedirectTitles;
@@ -346,12 +342,12 @@ class ApiPageSet extends ApiQueryBase {
 
        /**
         * Populate this PageSet from a rowset returned from the database
-        * @param $db Database object
-        * @param $queryResult Query result object
+        * @param $db DatabaseBase object
+        * @param $queryResult ResultWrapper Query result object
         */
        public function populateFromQueryResult( $db, $queryResult ) {
                $this->profileIn();
-               $this->initFromQueryResult( $db, $queryResult );
+               $this->initFromQueryResult( $queryResult );
                $this->profileOut();
        }
 
@@ -430,7 +426,7 @@ class ApiPageSet extends ApiQueryBase {
                $this->profileDBOut();
 
                // Hack: get the ns:titles stored in array(ns => array(titles)) format
-               $this->initFromQueryResult( $db, $res, $linkBatch->data, true ); // process Titles
+               $this->initFromQueryResult( $res, $linkBatch->data, true ); // process Titles
 
                // Resolve any found redirects
                $this->resolvePendingRedirects();
@@ -446,19 +442,25 @@ class ApiPageSet extends ApiQueryBase {
                }
 
                $pageids = array_map( 'intval', $pageids ); // paranoia
-               $set = array(
-                       'page_id' => $pageids
-               );
-               $db = $this->getDB();
+               $remaining = array_flip( $pageids );
 
-               // Get pageIDs data from the `page` table
-               $this->profileDBIn();
-               $res = $db->select( 'page', $this->getPageTableFields(), $set,
-                                       __METHOD__ );
-               $this->profileDBOut();
+               $pageids = self::getPositiveIntegers( $pageids );
 
-               $remaining = array_flip( $pageids );
-               $this->initFromQueryResult( $db, $res, $remaining, false );     // process PageIDs
+               $res = null;
+               if ( count( $pageids ) ) {
+                       $set = array(
+                               'page_id' => $pageids
+                       );
+                       $db = $this->getDB();
+
+                       // Get pageIDs data from the `page` table
+                       $this->profileDBIn();
+                       $res = $db->select( 'page', $this->getPageTableFields(), $set,
+                                               __METHOD__ );
+                       $this->profileDBOut();
+               }
+
+               $this->initFromQueryResult( $res, $remaining, false );  // process PageIDs
 
                // Resolve any found redirects
                $this->resolvePendingRedirects();
@@ -467,33 +469,40 @@ class ApiPageSet extends ApiQueryBase {
        /**
         * Iterate through the result of the query on 'page' table,
         * and for each row create and store title object and save any extra fields requested.
-        * @param $db Database
-        * @param $res DB Query result
+        * @param $res ResultWrapper DB Query result
         * @param $remaining array of either pageID or ns/title elements (optional).
         *        If given, any missing items will go to $mMissingPageIDs and $mMissingTitles
         * @param $processTitles bool Must be provided together with $remaining.
         *        If true, treat $remaining as an array of [ns][title]
         *        If false, treat it as an array of [pageIDs]
         */
-       private function initFromQueryResult( $db, $res, &$remaining = null, $processTitles = null ) {
+       private function initFromQueryResult( $res, &$remaining = null, $processTitles = null ) {
                if ( !is_null( $remaining ) && is_null( $processTitles ) ) {
                        ApiBase::dieDebug( __METHOD__, 'Missing $processTitles parameter when $remaining is provided' );
                }
 
-               foreach ( $res as $row ) {
-                       $pageId = intval( $row->page_id );
+               $usernames = array();
+               if ( $res ) {
+                       foreach ( $res as $row ) {
+                               $pageId = intval( $row->page_id );
+
+                               // Remove found page from the list of remaining items
+                               if ( isset( $remaining ) ) {
+                                       if ( $processTitles ) {
+                                               unset( $remaining[$row->page_namespace][$row->page_title] );
+                                       } else {
+                                               unset( $remaining[$pageId] );
+                                       }
+                               }
 
-                       // Remove found page from the list of remaining items
-                       if ( isset( $remaining ) ) {
-                               if ( $processTitles ) {
-                                       unset( $remaining[$row->page_namespace][$row->page_title] );
-                               } else {
-                                       unset( $remaining[$pageId] );
+                               // Store any extra fields requested by modules
+                               $this->processDbRow( $row );
+
+                               // Need gender information
+                               if( MWNamespace::hasGenderDistinction( $row->page_namespace ) ) {
+                                       $usernames[] = $row->page_title;
                                }
                        }
-
-                       // Store any extra fields requested by modules
-                       $this->processDbRow( $row );
                }
 
                if ( isset( $remaining ) ) {
@@ -501,12 +510,17 @@ class ApiPageSet extends ApiQueryBase {
                        if ( $processTitles ) {
                                // The remaining titles in $remaining are non-existent pages
                                foreach ( $remaining as $ns => $dbkeys ) {
-                                       foreach ( $dbkeys as $dbkey => $unused ) {
+                                       foreach ( array_keys( $dbkeys ) as $dbkey ) {
                                                $title = Title::makeTitle( $ns, $dbkey );
                                                $this->mAllPages[$ns][$dbkey] = $this->mFakePageId;
                                                $this->mMissingTitles[$this->mFakePageId] = $title;
                                                $this->mFakePageId--;
                                                $this->mTitles[] = $title;
+
+                                               // need gender information
+                                               if( MWNamespace::hasGenderDistinction( $ns ) ) {
+                                                       $usernames[] = $dbkey;
+                                               }
                                        }
                                }
                        } else {
@@ -518,6 +532,10 @@ class ApiPageSet extends ApiQueryBase {
                                }
                        }
                }
+
+               // Get gender information
+               $genderCache = GenderCache::singleton();
+               $genderCache->doQuery( $usernames, __METHOD__ );
        }
 
        /**
@@ -535,21 +553,25 @@ class ApiPageSet extends ApiQueryBase {
                $pageids = array();
                $remaining = array_flip( $revids );
 
-               $tables = array( 'revision', 'page' );
-               $fields = array( 'rev_id', 'rev_page' );
-               $where = array( 'rev_id' => $revids, 'rev_page = page_id' );
-
-               // Get pageIDs data from the `page` table
-               $this->profileDBIn();
-               $res = $db->select( $tables, $fields, $where,  __METHOD__ );
-               foreach ( $res as $row ) {
-                       $revid = intval( $row->rev_id );
-                       $pageid = intval( $row->rev_page );
-                       $this->mGoodRevIDs[$revid] = $pageid;
-                       $pageids[$pageid] = '';
-                       unset( $remaining[$revid] );
+               $revids = self::getPositiveIntegers( $revids );
+
+               if ( count( $revids ) ) {
+                       $tables = array( 'revision', 'page' );
+                       $fields = array( 'rev_id', 'rev_page' );
+                       $where = array( 'rev_id' => $revids, 'rev_page = page_id' );
+
+                       // Get pageIDs data from the `page` table
+                       $this->profileDBIn();
+                       $res = $db->select( $tables, $fields, $where,  __METHOD__ );
+                       foreach ( $res as $row ) {
+                               $revid = intval( $row->rev_id );
+                               $pageid = intval( $row->rev_page );
+                               $this->mGoodRevIDs[$revid] = $pageid;
+                               $pageids[$pageid] = '';
+                               unset( $remaining[$revid] );
+                       }
+                       $this->profileDBOut();
                }
-               $this->profileDBOut();
 
                $this->mMissingRevIDs = array_keys( $remaining );
 
@@ -589,7 +611,7 @@ class ApiPageSet extends ApiQueryBase {
                                $this->profileDBOut();
 
                                // Hack: get the ns:titles stored in array(ns => array(titles)) format
-                               $this->initFromQueryResult( $db, $res, $linkBatch->data, true );
+                               $this->initFromQueryResult( $res, $linkBatch->data, true );
                        }
                }
        }
@@ -611,16 +633,17 @@ class ApiPageSet extends ApiQueryBase {
                        array(
                                'rd_from',
                                'rd_namespace',
+                               'rd_fragment',
+                               'rd_interwiki',
                                'rd_title'
                        ), array( 'rd_from' => array_keys( $this->mPendingRedirectIDs ) ),
                        __METHOD__
                );
                $this->profileDBOut();
-
                foreach ( $res as $row ) {
                        $rdfrom = intval( $row->rd_from );
                        $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
-                       $to = Title::makeTitle( $row->rd_namespace, $row->rd_title )->getPrefixedText();
+                       $to = Title::makeTitle( $row->rd_namespace, $row->rd_title, $row->rd_fragment, $row->rd_interwiki );
                        unset( $this->mPendingRedirectIDs[$rdfrom] );
                        if ( !isset( $this->mAllPages[$row->rd_namespace][$row->rd_title] ) ) {
                                $lb->add( $row->rd_namespace, $row->rd_title );
@@ -632,14 +655,14 @@ class ApiPageSet extends ApiQueryBase {
                        // We found pages that aren't in the redirect table
                        // Add them
                        foreach ( $this->mPendingRedirectIDs as $id => $title ) {
-                               $article = new Article( $title );
-                               $rt = $article->insertRedirect();
+                               $page = WikiPage::factory( $title );
+                               $rt = $page->insertRedirect();
                                if ( !$rt ) {
                                        // What the hell. Let's just ignore this
                                        continue;
                                }
                                $lb->addObj( $rt );
-                               $this->mRedirectTitles[$title->getPrefixedText()] = $rt->getPrefixedText();
+                               $this->mRedirectTitles[$title->getPrefixedText()] = $rt;
                                unset( $this->mPendingRedirectIDs[$id] );
                        }
                }
@@ -656,6 +679,9 @@ class ApiPageSet extends ApiQueryBase {
         * @return LinkBatch
         */
        private function processTitlesArray( $titles ) {
+               $genderCache = GenderCache::singleton();
+               $genderCache->doTitlesArray( $titles, __METHOD__ );
+
                $linkBatch = new LinkBatch();
 
                foreach ( $titles as $title ) {
@@ -685,7 +711,6 @@ class ApiPageSet extends ApiQueryBase {
                                        $titleWasConverted = $unconvertedTitle !== $titleObj->getPrefixedText();
                                }
 
-
                                if ( $titleObj->getNamespace() < 0 ) {
                                        // Handle Special and Media pages
                                        $titleObj = $titleObj->fixSpecialName();
@@ -712,7 +737,26 @@ class ApiPageSet extends ApiQueryBase {
                return $linkBatch;
        }
 
-       protected function getAllowedParams() {
+       /**
+        * Returns the input array of integers with all values < 0 removed
+        *
+        * @param $array array
+        * @return array
+        */
+       private static function getPositiveIntegers( $array ) {
+               // bug 25734 API: possible issue with revids validation
+               // It seems with a load of revision rows, MySQL gets upset
+               // Remove any < 0 integers, as they can't be valid
+               foreach( $array as $i => $int ) {
+                       if ( $int < 0 ) {
+                               unset( $array[$i] );
+                       }
+               }
+
+               return $array;
+       }
+
+       public function getAllowedParams() {
                return array(
                        'titles' => array(
                                ApiBase::PARAM_ISMULTI => true
@@ -728,7 +772,7 @@ class ApiPageSet extends ApiQueryBase {
                );
        }
 
-       protected function getParamDescription() {
+       public function getParamDescription() {
                return array(
                        'titles' => 'A list of titles to work on',
                        'pageids' => 'A list of page IDs to work on',