return $this->mIsSysop;
}
- /**
- * Check whether the current user is allowed to use high limits
- * @return bool
- */
public function canApiHighLimits() {
if (!isset($this->mCanApiHighLimits)) {
global $wgUser;
return $this->mCanApiHighLimits;
}
- /**
- * Check whether the user wants us to show version information in the API help
- * @return bool
- */
public function getShowVersions() {
return $this->mShowVersions;
}
$fld_editcount = isset($prop['editcount']);
$fld_groups = isset($prop['groups']);
$fld_registration = isset($prop['registration']);
- $fld_blockinfo = isset($prop['blockinfo']);
} else {
- $fld_editcount = $fld_groups = $fld_registration = $fld_blockinfo = false;
+ $fld_editcount = $fld_groups = $fld_registration = false;
}
$limit = $params['limit'];
+ $tables = $db->tableName('user');
if( !is_null( $params['from'] ) )
- $this->addWhere( 'u1.user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) );
+ $this->addWhere( 'user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) );
if( isset( $params['prefix'] ) )
- $this->addWhere( 'u1.user_name LIKE "' . $db->escapeLike( self::keyToTitle( $params['prefix'] ) ) . '%"' );
+ $this->addWhere( 'user_name LIKE "' . $db->escapeLike( self::keyToTitle( $params['prefix'] ) ) . '%"' );
- $join = false;
- $tables = array('user');
- $types = array();
- $conds = array();
- $aliases = array('u1');
if (!is_null($params['group'])) {
// Filter only users that belong to a given group
- $this->addTables('user_groups', 'ug1');
- $this->addWhere('ug1.ug_user=u1.user_id');
+ $tblName = $db->tableName('user_groups');
+ $tables = "$tables INNER JOIN $tblName ug1 ON ug1.ug_user=user_id";
$this->addWhereFld('ug1.ug_group', $params['group']);
}
+
if ($fld_groups) {
// Show the groups the given users belong to
// request more than needed to avoid not getting all rows that belong to one user
$groupCount = count(User::getAllGroups());
$sqlLimit = $limit+$groupCount+1;
-
- $join = true;
- $tables[] = 'user_groups';
- $types[] = ApiQueryBase::LEFT_JOIN;
- $conds[] = 'ug2.ug_user=u1.user_id';
- $aliases[] = 'ug2';
+
+ $tblName = $db->tableName('user_groups');
+ $tables = "$tables LEFT JOIN $tblName ug2 ON ug2.ug_user=user_id";
$this->addFields('ug2.ug_group ug_group2');
} else {
$sqlLimit = $limit+1;
}
- if ($fld_blockinfo) {
- $join = true;
- $tables[] = 'ipblocks';
- $types[] = ApiQueryBase::LEFT_JOIN;
- $conds[] = 'ipb_user=u1.user_id';
- $aliases[] = null;
-
- $tables[] = 'user';
- $types[] = ApiQueryBase::LEFT_JOIN;
- $conds[] = 'ipb_by=u2.user_id';
- $aliases[] = 'u2';
- $this->addFields(array('ipb_reason', 'u2.user_name AS blocker_name'));
- }
-
- if ($join) {
- $this->addJoin($tables, $types, $conds, $aliases);
- } else {
- $this->addTables('user', 'u1');
- }
+
+ if ($fld_registration)
+ $this->addFields('user_registration');
$this->addOption('LIMIT', $sqlLimit);
+ $this->addTables($tables);
- $this->addFields('u1.user_name');
- $this->addFieldsIf('u1.user_editcount', $fld_editcount);
- $this->addFieldsIf('u1.user_registration', $fld_registration);
+ $this->addFields('user_name');
+ $this->addFieldsIf('user_editcount', $fld_editcount);
- $this->addOption('ORDER BY', 'u1.user_name');
+ $this->addOption('ORDER BY', 'user_name');
$res = $this->select(__METHOD__);
$lastUserData['editcount'] = intval($row->user_editcount);
if ($fld_registration)
$lastUserData['registration'] = wfTimestamp(TS_ISO_8601, $row->user_registration);
- if ($fld_blockinfo && !is_null($row->blocker_name)) {
- $lastUserData['blockedby'] = $row->blocker_name;
- $lastUserData['blockreason'] = $row->ipb_reason;
- }
}
'editcount',
'groups',
'registration',
- 'blockinfo'
)
),
'limit' => array (
}
if($params['filterlanglinks'] == 'withoutlanglinks') {
- $this->addJoin(
- array('page', 'langlinks'),
- array(ApiQueryBase::LEFT_JOIN),
- array('page_id=ll_from'));
+ $pageName = $this->getDB()->tableName('page');
+ $llName = $this->getDB()->tableName('langlinks');
+ $tables = "$pageName LEFT JOIN $llName ON page_id=ll_from";
$this->addWhere('ll_from IS NULL');
+ $this->addTables($tables);
$forceNameTitleIndex = false;
} else if($params['filterlanglinks'] == 'withlanglinks') {
$this->addTables(array('page', 'langlinks'));
* LIMIT 11 ORDER BY pl_from
*/
$db = $this->getDb();
- $this->addTables(array($this->bl_table, 'page'));
- $this->addWhere("{$this->bl_from}=page_id");
+ list($tblpage, $tbllinks) = $db->tableNamesN('page', $this->bl_table);
+ $this->addTables("$tbllinks JOIN $tblpage ON {$this->bl_from}=page_id");
if(is_null($resultPageSet))
$this->addFields(array('page_id', 'page_title', 'page_namespace'));
else
* LIMIT 11 ORDER BY pl_namespace, pl_title, pl_from
*/
$db = $this->getDb();
- $this->addTables(array($this->bl_table, 'page'));
- $this->addWhere("{$this->bl_from}=page_id");
+ list($tblpage, $tbllinks) = $db->tableNamesN('page', $this->bl_table);
+ $this->addTables("$tbllinks JOIN $tblpage ON {$this->bl_from}=page_id");
if(is_null($resultPageSet))
$this->addFields(array('page_id', 'page_title', 'page_namespace', 'page_is_redirect'));
else
}
protected function processContinue() {
+ $pageSet = $this->getPageSet();
+ $count = $pageSet->getTitleCount();
+
if (!is_null($this->params['continue']))
$this->parseContinueParam();
else {
$title = $this->params['title'];
if (!is_null($title)) {
$this->rootTitle = Title :: newFromText($title);
- } else {
- $this->dieUsageMsg(array('missingparam', "title"));
+ } else { // This case is obsolete. Will support this for a while
+ if ($count !== 1)
+ $this->dieUsage("The {$this->getModuleName()} query requires one title to start", 'bad_title_count');
+ $this->rootTitle = current($pageSet->getTitles()); // only one title there
+ $this->setWarning('Using titles parameter is obsolete for this list. Use ' . $this->encodeParamName('title') . ' instead.');
}
}
abstract class ApiQueryBase extends ApiBase {
private $mQueryModule, $mDb, $tables, $where, $fields, $options;
-
- const LEFT_JOIN = 1;
- const RIGHT_JOIN = 2;
public function __construct($query, $moduleName, $paramPrefix = '') {
parent :: __construct($query->getMain(), $moduleName, $paramPrefix);
$this->resetQueryParams();
}
- /**
- * Blank the internal arrays with query parameters
- */
protected function resetQueryParams() {
$this->tables = array ();
$this->where = array ();
$this->options = array ();
}
- /**
- * Add a set of tables to the internal array
- * @param mixed $tables Table name or array of table names
- * @param mixed $alias Table alias, or null for no alias. Cannot be used with multiple tables
- */
protected function addTables($tables, $alias = null) {
if (is_array($tables)) {
if (!is_null($alias))
}
}
- /**
- * Add a JOIN to the internal array.
- *
- * Example for: a LEFT JOIN page AS b ON foo=bar RIGHT JOIN c ON foo=baz AND bar=3
- *
- * addJoin(array('a', 'page', 'c'), array(ApiQueryBase::LEFT_JOIN, ApiQueryBase::RIGHT_JOIN),
- * array('foo=bar', array('foo=baz', 'bar' => 3), array(null, 'b', null))
- * @param array $tables Array of table names
- * @param array $types Array of join types (either LEFT_JOIN or RIGHT_JOIN)
- * @param array $onClauses Array of ON clauses. Each element is formed like addWhere()'s parameter
- * @param array $aliases Array of table aliases, or null for no alias
- */
- protected function addJoin($tables, $types, $onClauses, $aliases = null) {
- if(is_null($aliases))
- foreach($tables as $unused)
- $aliases[] = null;
- if(!is_array($tables) || !is_array($types) || !is_array($onClauses) || !is_array($aliases))
- ApiBase::dieDebug(__METHOD__, 'This function only takes arrays as parameters');
- $sql = $this->getDB()->tableName($tables[0]) . (is_null($aliases[0]) ? "" : " {$aliases[0]}");
- for($i = 0; $i < count($tables) - 1; $i++)
- {
- if($types[$i] == self::LEFT_JOIN)
- $join = "LEFT JOIN";
- else if($types[$i] == self::RIGHT_JOIN)
- $join = "RIGHT JOIN";
- else
- ApiBase::dieDebug(__METHOD__, "Invalid join type {$types[$i]}");
-
- if(is_array($onClauses[$i]))
- $on = $this->getDB()->makeList($onClauses[$i], LIST_AND);
- else
- $on = $onClauses[$i];
- $alias = $aliases[$i+1];
- $tblname = $this->getDB()->tableName($tables[$i+1]) . (is_null($alias) ? "" : " $alias");
- $sql = "$sql $join $tblname ON $on";
- }
- $this->addTables($sql);
- }
-
- /**
- * Add a set of fields to select to the internal array
- * @param mixed $value Field name or array of field names
- */
protected function addFields($value) {
if (is_array($value))
$this->fields = array_merge($this->fields, $value);
$this->fields[] = $value;
}
- /**
- * Same as addFields(), but add the fields only if a condition is met
- * @param mixed $value See addFields()
- * @param bool $condition If false, do nothing
- * @return bool $condition
- */
protected function addFieldsIf($value, $condition) {
if ($condition) {
$this->addFields($value);
return false;
}
- /**
- * Add a set of WHERE clauses to the internal array.
- * Clauses can be formatted as 'foo=bar' or array('foo' => 'bar'),
- * the latter only works if the value is a constant (i.e. not another field)
- *
- * For example, array('foo=bar', 'baz' => 3, 'bla' => 'foo') translates
- * to "foo=bar AND baz='3' AND bla='foo'"
- * @param mixed $value String or array
- */
protected function addWhere($value) {
if (is_array($value))
$this->where = array_merge($this->where, $value);
$this->where[] = $value;
}
- /**
- * Same as addWhere(), but add the WHERE clauses only if a condition is met
- * @param mixed $value See addWhere()
- * @param bool $condition If false, do nothing
- * @return bool $condition
- */
protected function addWhereIf($value, $condition) {
if ($condition) {
$this->addWhere($value);
return false;
}
- /**
- * Equivalent to addWhere(array($field => $value))
- * @param string $field Field name
- * @param string $value Value; ignored if nul;
- */
protected function addWhereFld($field, $value) {
if (!is_null($value))
$this->where[$field] = $value;
}
- /**
- * Add a WHERE clause corresponding to a range, and an ORDER BY
- * clause to sort in the right direction
- * @param string $field Field name
- * @param string $dir If 'newer', sort in ascending order, otherwise sort in descending order
- * @param string $start Value to start the list at. If $dir == 'newer' this is the lower boundary, otherwise it's the upper boundary
- * @param string $end Value to end the list at. If $dir == 'newer' this is the upper boundary, otherwise it's the lower boundary
- */
protected function addWhereRange($field, $dir, $start, $end) {
$isDirNewer = ($dir === 'newer');
$after = ($isDirNewer ? '>=' : '<=');
$this->addOption('ORDER BY', $this->options['ORDER BY'] . ', ' . $order);
}
- /**
- * Add an option such as LIMIT or USE INDEX
- * @param string $name Option name
- * @param string $value Option value
- */
protected function addOption($name, $value = null) {
if (is_null($value))
$this->options[] = $name;
$this->options[$name] = $value;
}
- /**
- * Execute a SELECT query based on the values in the internal arrays
- * @param string $method Function the query should be attributed to. You should usually use __METHOD__ here
- * @return ResultWrapper
- */
protected function select($method) {
// getDB has its own profileDBIn/Out calls
return $res;
}
- /**
- * Estimate the row count for the SELECT query that would be run if we
- * called select() right now, and check if it's acceptable.
- * @return bool true if acceptable, false otherwise
- */
protected function checkRowCount() {
$db = $this->getDB();
$this->profileDBIn();
return true;
}
- /**
- * Add information (title and namespace) about a Title object to a result array
- * @param array $arr Result array à la ApiResult
- * @param Title $title Title object
- * @param string $prefix Module prefix
- */
public static function addTitleInfo(&$arr, $title, $prefix='') {
$arr[$prefix . 'ns'] = intval($title->getNamespace());
$arr[$prefix . 'title'] = $title->getPrefixedText();
/**
* Override this method to request extra fields from the pageSet
* using $pageSet->requestField('fieldName')
- * @param ApiPageSet $pageSet
*/
public function requestExtraData($pageSet) {
}
/**
* Get the main Query module
- * @return ApiQuery
*/
public function getQuery() {
return $this->mQueryModule;
}
/**
- * Add a sub-element under the page element with the given page ID
- * @param int $pageId Page ID
- * @param array $data Data array à la ApiResult
+ * Add sub-element under the page element with the given pageId.
*/
protected function addPageSubItems($pageId, $data) {
$result = $this->getResult();
$data);
}
- /**
- * Set a query-continue value
- * @param $paramName Parameter name
- * @param $paramValue Parameter value
- */
protected function setContinueEnumParameter($paramName, $paramValue) {
$paramName = $this->encodeParamName($paramName);
$msg = array( $paramName => $paramValue );
+
+// This is an alternative continue format as a part of the URL string
+// ApiResult :: setContent($msg, $paramName . '=' . urlencode($paramValue));
+
$this->getResult()->addValue('query-continue', $this->getModuleName(), $msg);
}
/**
* Get the Query database connection (readonly)
- * @return Database
*/
protected function getDB() {
if (is_null($this->mDb))
* If no such connection has been requested before, it will be created.
* Subsequent calls with the same $name will return the same connection
* as the first, regardless of $db or $groups new values.
- * @param string $name Name to assign to the database connection
- * @param int $db One of the DB_* constants
- * @param array $groups Query groups
- * @return Database
*/
public function selectNamedDB($name, $db, $groups) {
$this->mDb = $this->getQuery()->getNamedDB($name, $db, $groups);
/**
* Get the PageSet object to work on
- * @return ApiPageSet
+ * @return ApiPageSet data
*/
protected function getPageSet() {
return $this->getQuery()->getPageSet();
* This is a very simplistic utility function
* to convert a non-namespaced title string to a db key.
* It will replace all ' ' with '_'
- * @param string $title Page title with spaces
- * @return string Page title with underscores
*/
public static function titleToKey($title) {
return str_replace(' ', '_', $title);
}
- /**
- * The inverse of titleToKey()
- * @param string $key Page title with underscores
- * @return string Page title with spaces
- */
public static function keyToTitle($key) {
return str_replace('_', ' ', $key);
}
- /**
- * Check whether the current user requested a certain token and
- * is actually allowed to request it.
- * @param array $tokenArr Array of tokens the user requested
- * @param string $action Action to check for
- * @return bool true if the user requested the token and is allowed to, false otherwise
- */
public function getTokenFlag($tokenArr, $action) {
if ($this->getMain()->getRequest()->getVal('callback') !== null) {
// Don't do any session-specific data.
return false;
}
- /**
- * Get version string for use in the API help output
- * @return string
- */
public static function getBaseVersion() {
return __CLASS__ . ': $Id$';
}
$this->mIsGenerator = false;
}
- /**
- * Switch this module to generator mode. By default, generator mode is
- * switched off and the module acts like a normal query module.
- */
public function setGeneratorMode() {
$this->mIsGenerator = true;
}
$hideLogs = LogEventsList::getExcludeClause($db);
if($hideLogs !== false)
$this->addWhere($hideLogs);
-
- $this->addTables('user');
- $this->addWhere('user_id=log_user');
- $this->addJoin(
- array('logging', 'page'),
- array(ApiQueryBase::LEFT_JOIN),
- array(
- array( 'log_title=page_title',
- 'log_namespace=page_namespace'
- )));
+
+ $this->addOption('STRAIGHT_JOIN');
+ $this->addTables("$tbl_logging LEFT OUTER JOIN $tbl_page ON " .
+ "log_namespace=page_namespace AND log_title=page_title " .
+ "INNER JOIN $tbl_user ON user_id=log_user");
$this->addFields(array (
'log_type',
$this->addFieldsIf('rc_patrolled', $this->fld_patrolled);
if($this->fld_redirect || isset($show['redirect']) || isset($show['!redirect']))
{
- $this->addJoin(
- array('page', 'recentchanges'),
- array(ApiQueryBase::RIGHT_JOIN),
- array(array(
- 'page_namespace=rc_namespace',
- 'page_title=rc_title')));
+ $page = $db->tableName('page');
+ $tables = "$page RIGHT JOIN $rc FORCE INDEX(rc_timestamp) ON page_namespace=rc_namespace AND page_title=rc_title";
$this->addFields('page_is_redirect');
- } else {
- $this->addTables('recentchanges');
}
- } else {
- $this->addTables('recentchanges');
}
+ if(!isset($tables))
+ $tables = "$rc FORCE INDEX(rc_timestamp)";
+ $this->addTables($tables);
/* Specify the limit for our query. It's $limit+1 because we (possibly) need to
* generate a "continue" parameter, to allow paging. */
$this->addOption('LIMIT', $limit +1);
$res = $this->select(__METHOD__);
$data = array();
- $langNames = Language::getLanguageNames();
while($row = $db->fetchObject($res))
{
$val = array();
$val['prefix'] = $row->iw_prefix;
- if($row->iw_local == '1')
+ if ($row->iw_local == '1')
$val['local'] = '';
// $val['trans'] = intval($row->iw_trans); // should this be exposed?
- if(isset($langNames[$row->iw_prefix]))
- $val['language'] = $langNames[$row->iw_prefix];
$val['url'] = $row->iw_url;
$data[] = $val;
//We're after the revision table, and the corresponding page row for
//anything we retrieve.
- $this->addJoin(
- array('revision', 'page'),
- array(ApiQueryBase::LEFT_JOIN),
- array('page_id=rev_page'));
+ list ($tbl_page, $tbl_revision) = $this->getDB()->tableNamesN('page', 'revision');
+ $this->addTables("$tbl_revision LEFT OUTER JOIN $tbl_page ON page_id=rev_page");
$this->addWhereFld('rev_deleted', 0);
// We only want pages by the specified users.
return $retval;
$db = $this->getDb();
+ $userTable = $db->tableName('user');
+ $tables = "$userTable AS u1";
$this->addFields('u1.user_name');
$this->addWhereFld('u1.user_name', $goodNames);
$this->addFieldsIf('u1.user_editcount', isset($this->prop['editcount']));
- $this->addFieldsIf('u1.user_registration', isset($this->prop['registration']));
- $join = false;
- $tables = array('user');
- $types = array();
- $conds = array();
- $aliases = array('u1');
if(isset($this->prop['groups'])) {
- $join = true;
- $tables[] = 'user_groups';
- $types[] = ApiQueryBase::LEFT_JOIN;
- $conds[] = 'ug_user=u1.user_id';
- $aliases[] = null;
+ $ug = $db->tableName('user_groups');
+ $tables = "$tables LEFT JOIN $ug ON ug_user=u1.user_id";
$this->addFields('ug_group');
}
if(isset($this->prop['blockinfo'])) {
- $join = true;
- $tables[] = 'ipblocks';
- $types[] = ApiQueryBase::LEFT_JOIN;
- $conds[] = 'ipb_user=u1.user_id';
- $aliases[] = null;
-
- $tables[] = 'user';
- $types[] = ApiQueryBase::LEFT_JOIN;
- $conds[] = 'ipb_by=u2.user_id';
- $aliases[] = 'u2';
+ $ipb = $db->tableName('ipblocks');
+ $tables = "$tables LEFT JOIN $ipb ON ipb_user=u1.user_id";
+ $tables = "$tables LEFT JOIN $userTable AS u2 ON ipb_by=u2.user_id";
$this->addFields(array('ipb_reason', 'u2.user_name AS blocker_name'));
}
-
- if($join)
- $this->addJoin($tables, $types, $conds, $aliases);
- else
- $this->addTables('user', 'u1');
+ $this->addTables($tables);
$data = array();
$res = $this->select(__METHOD__);
$data[$r->user_name]['name'] = $r->user_name;
if(isset($this->prop['editcount']))
$data[$r->user_name]['editcount'] = $r->user_editcount;
- if(isset($this->prop['registration']))
- $data[$r->user_name]['registration'] = wfTimestamp(TS_ISO_8601, $r->user_registration);
if(isset($this->prop['groups']))
// This row contains only one group, others will be added from other rows
if(!is_null($r->ug_group))
ApiBase :: PARAM_TYPE => array (
'blockinfo',
'groups',
- 'editcount',
- 'registration'
+ 'editcount'
)
),
'users' => array(