Merge "Revert "(bug 30625) Add, to every API upload response, the warnings raised.""
[lhc/web/wiklou.git] / includes / api / ApiQueryBase.php
index 61a1072..92fabdd 100644 (file)
@@ -1,9 +1,8 @@
 <?php
-
 /**
- * Created on Sep 7, 2006
  *
- * API for MediaWiki 1.8+
+ *
+ * Created on Sep 7, 2006
  *
  * Copyright © 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
  *
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
  */
 
-if ( !defined( 'MEDIAWIKI' ) ) {
-       // Eclipse helper - will be ignored in production
-       require_once( 'ApiBase.php' );
-}
-
 /**
  * This is a base class for all Query modules.
  * It provides some common functionality such as constructing various SQL
@@ -39,13 +35,33 @@ abstract class ApiQueryBase extends ApiBase {
 
        private $mQueryModule, $mDb, $tables, $where, $fields, $options, $join_conds;
 
-       public function __construct( $query, $moduleName, $paramPrefix = '' ) {
+       /**
+        * @param $query ApiBase
+        * @param $moduleName string
+        * @param $paramPrefix string
+        */
+       public function __construct( ApiBase $query, $moduleName, $paramPrefix = '' ) {
                parent::__construct( $query->getMain(), $moduleName, $paramPrefix );
                $this->mQueryModule = $query;
                $this->mDb = null;
                $this->resetQueryParams();
        }
 
+       /**
+        * Get the cache mode for the data generated by this module. Override
+        * this in the module subclass. For possible return values and other
+        * details about cache modes, see ApiMain::setCacheMode()
+        *
+        * Public caching will only be allowed if *all* the modules that supply
+        * data for a given request return a cache mode of public.
+        *
+        * @param $params
+        * @return string
+        */
+       public function getCacheMode( $params ) {
+               return 'private';
+       }
+
        /**
         * Blank the internal arrays with query parameters
         */
@@ -71,22 +87,13 @@ abstract class ApiQueryBase extends ApiBase {
                        $this->tables = array_merge( $this->tables, $tables );
                } else {
                        if ( !is_null( $alias ) ) {
-                               $tables = $this->getAliasedName( $tables, $alias );
+                               $this->tables[$alias] = $tables;
+                       } else {
+                               $this->tables[] = $tables;
                        }
-                       $this->tables[] = $tables;
                }
        }
 
-       /**
-        * Get the SQL for a table name with alias
-        * @param $table string Table name
-        * @param $alias string Alias
-        * @return string SQL
-        */
-       protected function getAliasedName( $table, $alias ) {
-               return $this->getDB()->tableName( $table ) . ' ' . $alias;
-       }
-
        /**
         * Add a set of JOIN conditions to the internal array
         *
@@ -105,7 +112,7 @@ abstract class ApiQueryBase extends ApiBase {
 
        /**
         * Add a set of fields to select to the internal array
-        * @param $value mixed Field name or array of field names
+        * @param $value array|string Field name or array of field names
         */
        protected function addFields( $value ) {
                if ( is_array( $value ) ) {
@@ -117,7 +124,7 @@ abstract class ApiQueryBase extends ApiBase {
 
        /**
         * Same as addFields(), but add the fields only if a condition is met
-        * @param $value mixed See addFields()
+        * @param $value array|string See addFields()
         * @param $condition bool If false, do nothing
         * @return bool $condition
         */
@@ -155,7 +162,7 @@ abstract class ApiQueryBase extends ApiBase {
        /**
         * Same as addWhere(), but add the WHERE clauses only if a condition is met
         * @param $value mixed See addWhere()
-        * @param $condition boolIf false, do nothing
+        * @param $condition bool If false, do nothing
         * @return bool $condition
         */
        protected function addWhereIf( $value, $condition ) {
@@ -207,14 +214,29 @@ abstract class ApiQueryBase extends ApiBase {
 
                if ( $sort ) {
                        $order = $field . ( $isDirNewer ? '' : ' DESC' );
-                       if ( !isset( $this->options['ORDER BY'] ) ) {
-                               $this->addOption( 'ORDER BY', $order );
-                       } else {
-                               $this->addOption( 'ORDER BY', $this->options['ORDER BY'] . ', ' . $order );
-                       }
+                       // Append ORDER BY
+                       $optionOrderBy = isset( $this->options['ORDER BY'] ) ? (array)$this->options['ORDER BY'] : array();
+                       $optionOrderBy[] = $order;
+                       $this->addOption( 'ORDER BY', $optionOrderBy );
                }
        }
 
+       /**
+        * Add a WHERE clause corresponding to a range, similar to addWhereRange,
+        * but converts $start and $end to database timestamps.
+        * @see addWhereRange
+        * @param $field
+        * @param $dir
+        * @param $start
+        * @param $end
+        * @param $sort bool
+        */
+       protected function addTimestampWhereRange( $field, $dir, $start, $end, $sort = true ) {
+               $db = $this->getDb();
+               $this->addWhereRange( $field, $dir,
+                       $db->timestampOrNull( $start ), $db->timestampOrNull( $end ), $sort );
+       }
+
        /**
         * Add an option such as LIMIT or USE INDEX. If an option was set
         * before, the old value will be overwritten
@@ -233,14 +255,23 @@ abstract class ApiQueryBase extends ApiBase {
         * Execute a SELECT query based on the values in the internal arrays
         * @param $method string Function the query should be attributed to.
         *  You should usually use __METHOD__ here
+        * @param $extraQuery array Query data to add but not store in the object
+        *  Format is array( 'tables' => ..., 'fields' => ..., 'where' => ..., 'options' => ..., 'join_conds' => ... )
         * @return ResultWrapper
         */
-       protected function select( $method ) {
+       protected function select( $method, $extraQuery = array() ) {
+
+               $tables = array_merge( $this->tables, isset( $extraQuery['tables'] ) ? (array)$extraQuery['tables'] : array() );
+               $fields = array_merge( $this->fields, isset( $extraQuery['fields'] ) ? (array)$extraQuery['fields'] : array() );
+               $where = array_merge( $this->where, isset( $extraQuery['where'] ) ? (array)$extraQuery['where'] : array() );
+               $options = array_merge( $this->options, isset( $extraQuery['options'] ) ? (array)$extraQuery['options'] : array() );
+               $join_conds = array_merge( $this->join_conds, isset( $extraQuery['join_conds'] ) ? (array)$extraQuery['join_conds'] : array() );
+
                // getDB has its own profileDBIn/Out calls
                $db = $this->getDB();
 
                $this->profileDBIn();
-               $res = $db->select( $this->tables, $this->fields, $this->where, $method, $this->options, $this->join_conds );
+               $res = $db->select( $tables, $fields, $where, $method, $options, $join_conds );
                $this->profileDBOut();
 
                return $res;
@@ -337,18 +368,20 @@ abstract class ApiQueryBase extends ApiBase {
        protected function setContinueEnumParameter( $paramName, $paramValue ) {
                $paramName = $this->encodeParamName( $paramName );
                $msg = array( $paramName => $paramValue );
-               $this->getResult()->disableSizeCheck();
-               $this->getResult()->addValue( 'query-continue', $this->getModuleName(), $msg );
-               $this->getResult()->enableSizeCheck();
+               $result = $this->getResult();
+               $result->disableSizeCheck();
+               $result->addValue( 'query-continue', $this->getModuleName(), $msg );
+               $result->enableSizeCheck();
        }
 
        /**
         * Get the Query database connection (read-only)
-        * @return Database
+        * @return DatabaseBase
         */
        protected function getDB() {
                if ( is_null( $this->mDb ) ) {
-                       $this->mDb = $this->getQuery()->getDB();
+                       $apiQuery = $this->getQuery();
+                       $this->mDb = $apiQuery->getDB();
                }
                return $this->mDb;
        }
@@ -359,7 +392,7 @@ abstract class ApiQueryBase extends ApiBase {
         * @param $name string Name to assign to the database connection
         * @param $db int One of the DB_* constants
         * @param $groups array Query groups
-        * @return Database
+        * @return DatabaseBase
         */
        public function selectNamedDB( $name, $db, $groups ) {
                $this->mDb = $this->getQuery()->getNamedDB( $name, $db, $groups );
@@ -426,6 +459,95 @@ abstract class ApiQueryBase extends ApiBase {
                return substr( $this->keyToTitle( $keyPart . 'x' ), 0, - 1 );
        }
 
+       /**
+        * Gets the personalised direction parameter description
+        *
+        * @param string $p ModulePrefix
+        * @param string $extraDirText Any extra text to be appended on the description
+        * @return array
+        */
+       public function getDirectionDescription( $p = '', $extraDirText = '' ) {
+               return array(
+                               "In which direction to enumerate{$extraDirText}",
+                               " newer          - List oldest first. Note: {$p}start has to be before {$p}end.",
+                               " older          - List newest first (default). Note: {$p}start has to be later than {$p}end.",
+                       );
+       }
+
+       /**
+        * @param $query String
+        * @param $protocol String
+        * @return null|string
+        */
+       public function prepareUrlQuerySearchString( $query = null, $protocol = null) {
+               $db = $this->getDb();
+               if ( !is_null( $query ) || $query != '' ) {
+                       if ( is_null( $protocol ) ) {
+                               $protocol = 'http://';
+                       }
+
+                       $likeQuery = LinkFilter::makeLikeArray( $query, $protocol );
+                       if ( !$likeQuery ) {
+                               $this->dieUsage( 'Invalid query', 'bad_query' );
+                       }
+
+                       $likeQuery = LinkFilter::keepOneWildcard( $likeQuery );
+                       return 'el_index ' . $db->buildLike( $likeQuery );
+               } elseif ( !is_null( $protocol ) ) {
+                       return 'el_index ' . $db->buildLike( "$protocol", $db->anyString() );
+               }
+
+               return null;
+       }
+
+       /**
+        * Filters hidden users (where the user doesn't have the right to view them)
+        * Also adds relevant block information
+        *
+        * @param bool $showBlockInfo
+        * @return void
+        */
+       public function showHiddenUsersAddBlockInfo( $showBlockInfo ) {
+               $userCanViewHiddenUsers = $this->getUser()->isAllowed( 'hideuser' );
+
+               if ( $showBlockInfo || !$userCanViewHiddenUsers ) {
+                       $this->addTables( 'ipblocks' );
+                       $this->addJoinConds( array(
+                               'ipblocks' => array( 'LEFT JOIN', 'ipb_user=user_id' ),
+                       ) );
+
+                       $this->addFields( 'ipb_deleted' );
+
+                       if ( $showBlockInfo ) {
+                               $this->addFields( array( 'ipb_id', 'ipb_by', 'ipb_by_text', 'ipb_reason', 'ipb_expiry' ) );
+                       }
+
+                       // Don't show hidden names
+                       if ( !$userCanViewHiddenUsers ) {
+                               $this->addWhere( 'ipb_deleted = 0 OR ipb_deleted IS NULL' );
+                       }
+               }
+       }
+
+       /**
+        * @param $hash string
+        * @return bool
+        */
+       public function validateSha1Hash( $hash ) {
+               return preg_match( '/[a-fA-F0-9]{40}/', $hash );
+       }
+
+       /**
+        * @param $hash string
+        * @return bool
+        */
+       public function validateSha1Base36Hash( $hash ) {
+               return preg_match( '/[a-zA-Z0-9]{31}/', $hash );
+       }
+
+       /**
+        * @return array
+        */
        public function getPossibleErrors() {
                return array_merge( parent::getPossibleErrors(), array(
                        array( 'invalidtitle', 'title' ),