Browse Source

...

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
cf10943cd3
  1. 90
      framework/db/ar/ActiveFinder.php
  2. 26
      framework/db/ar/ActiveRecord.php
  3. 117
      framework/db/dao/Query.php
  4. 9
      framework/db/dao/QueryBuilder.php
  5. 12
      tests/unit/framework/db/ar/ActiveRecordTest.php

90
framework/db/ar/ActiveFinder.php

@ -17,7 +17,8 @@ use yii\db\Exception;
/**
* ActiveFinder.php is ...
* todo: add SQL monitor
*
* todo: better handling on join() support in QueryBuilder: use regexp to detect table name and quote it
* todo: do not support anonymous parameter binding
* todo: add ActiveFinderBuilder
* todo: quote join/on part of the relational query
* todo: modify QueryBuilder about join() methods
@ -29,6 +30,7 @@ use yii\db\Exception;
* todo: lazy loading
* todo: scope
* todo: test via option
* todo: count, sum, exists
*
* @property integer $count
*
@ -80,6 +82,10 @@ class ActiveFinder extends \yii\base\Object implements \IteratorAggregate, \Arra
$this->query = new Query;
}
/**
* Executes query and returns all results as an array.
* @return array the query results. If the query results in nothing, an empty array will be returned.
*/
public function all()
{
if ($this->records === null) {
@ -89,15 +95,14 @@ class ActiveFinder extends \yii\base\Object implements \IteratorAggregate, \Arra
}
/**
* @param boolean $limitOne
* @return null|ActiveRecord
* Executes query and returns a single row of result.
* @return null|array|ActiveRecord the single row of query result. Depending on the setting of [[asArray]],
* the query result may be either an array or an ActiveRecord object. Null will be returned
* if the query results in nothing.
*/
public function one($limitOne = true)
public function one()
{
if ($this->records === null) {
if ($limitOne) {
$this->limit(1);
}
$this->records = $this->findRecords();
}
return isset($this->records[0]) ? $this->records[0] : null;
@ -442,96 +447,73 @@ class ActiveFinder extends \yii\base\Object implements \IteratorAggregate, \Arra
}
/**
* Appends an INNER JOIN part to the query.
* Appends a JOIN part to the query.
* The first parameter specifies what type of join it is.
* @param string $type the type of join, such as INNER JOIN, LEFT JOIN.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $condition the join condition that should appear in the ON part.
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return ActiveFinder the query object itself
* @return Query the query object itself
*/
public function join($table, $condition, $params = array())
public function join($type, $table, $on = '', $params = array())
{
if (is_array($params)) {
$this->query->join($table, $condition, $params);
} else {
call_user_func_array(array($this->query, __FUNCTION__), func_get_args());
}
$this->query->join($type, $table, $on, $params);
return $this;
}
/**
* Appends a LEFT OUTER JOIN part to the query.
* Appends an INNER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $condition the join condition that should appear in the ON part.
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return ActiveFinder the query object itself
*/
public function leftJoin($table, $condition, $params = array())
public function innerJoin($table, $on, $params = array())
{
if (is_array($params)) {
$this->query->leftJoin($table, $condition, $params);
} else {
call_user_func_array(array($this->query, __FUNCTION__), func_get_args());
}
$this->query->join($table, $on, $params);
return $this;
}
/**
* Appends a RIGHT OUTER JOIN part to the query.
* Appends a LEFT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $condition the join condition that should appear in the ON part.
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return ActiveFinder the query object itself
*/
public function rightJoin($table, $condition, $params = array())
{
if (is_array($params)) {
$this->query->rightJoin($table, $condition, $params);
} else {
call_user_func_array(array($this->query, __FUNCTION__), func_get_args());
}
return $this;
}
/**
* Appends a CROSS JOIN part to the query.
* Note that not all DBMS support CROSS JOIN.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @return ActiveFinder the query object itself
*/
public function crossJoin($table)
public function leftJoin($table, $on, $params = array())
{
$this->query->crossJoin($table);
$this->query->leftJoin($table, $on, $params);
return $this;
}
/**
* Appends a NATURAL JOIN part to the query.
* Note that not all DBMS support NATURAL JOIN.
* Appends a RIGHT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return ActiveFinder the query object itself
*/
public function naturalJoin($table)
public function rightJoin($table, $on, $params = array())
{
$this->query->naturalJoin($table);
$this->query->rightJoin($table, $on, $params);
return $this;
}
@ -746,7 +728,7 @@ class ActiveFinder extends \yii\base\Object implements \IteratorAggregate, \Arra
$rows = $command->queryAll();
if (!empty($this->with)) {
if (isset($joinTree)) {
foreach ($rows as $row) {
$joinTree->populateData($row);
}

26
framework/db/ar/ActiveRecord.php

@ -50,6 +50,17 @@ abstract class ActiveRecord extends Model
}
/**
* Returns the database connection used by this AR class.
* By default, the "db" application component is used as the database connection.
* You may override this method if you want to use a different database connection.
* @return Connection the database connection used by this AR class.
*/
public static function getDbConnection()
{
return \Yii::$application->getDb();
}
/**
* Creates an [[ActiveFinder]] instance for query purpose.
*
* Because [[ActiveFinder]] implements a set of query building methods,
@ -105,10 +116,6 @@ abstract class ActiveRecord extends Model
*/
public static function findBySql($sql, $params = array())
{
if (!is_array($params)) {
$params = func_get_args();
unset($params[0]);
}
$finder = static::createActiveFinder();
$finder->sql = $sql;
return $finder->params($params);
@ -155,17 +162,6 @@ abstract class ActiveRecord extends Model
}
/**
* Returns the database connection used by this AR class.
* By default, the "db" application component is used as the database connection.
* You may override this method if you want to use a different database connection.
* @return Connection the database connection used by this AR class.
*/
public static function getDbConnection()
{
return \Yii::$application->getDb();
}
/**
* Declares the name of the database table associated with this AR class.
* By default this method returns the class name as the table name by calling [[Text::camel2id()]].
* For example, 'Customer' becomes 'customer', and 'OrderDetail' becomes 'order_detail'.

117
framework/db/dao/Query.php

@ -169,17 +169,10 @@ class Query extends \yii\base\Object
* @param string|array $condition the conditions that will be put in the WHERE part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
*/
public function update($table, $columns, $condition = '', $params = array())
{
if (!is_array($params)) {
$params = func_get_args();
array_shift($params);
array_shift($params);
unset($params[0]);
}
$this->addParams($params);
$this->operation = array(__FUNCTION__, $table, $columns, $condition, array());
return $this;
@ -191,16 +184,10 @@ class Query extends \yii\base\Object
* @param string|array $condition the conditions that will be put in the WHERE part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
*/
public function delete($table, $condition = '', $params = array())
{
if (!is_array($params)) {
$params = func_get_args();
array_shift($params);
unset($params[0]);
}
$this->operation = array(__FUNCTION__, $table, $condition);
return $this->addParams($params);
}
@ -484,8 +471,6 @@ class Query extends \yii\base\Object
*
* @param string|array $condition the conditions that should be put in the WHERE part.
* @param array $params the parameters (name=>value) to be bound to the query.
* For anonymous parameters, they can alternatively be specified as separate parameters to this method.
* For example, `where('type=? AND status=?', 100, 1)`.
* @return Query the query object itself
* @see andWhere()
* @see orWhere()
@ -493,10 +478,6 @@ class Query extends \yii\base\Object
public function where($condition, $params = array())
{
$this->where = $condition;
if (!is_array($params)) {
$params = func_get_args();
unset($params[0]);
}
$this->addParams($params);
return $this;
}
@ -507,7 +488,6 @@ class Query extends \yii\base\Object
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
* @see where()
* @see orWhere()
@ -519,10 +499,6 @@ class Query extends \yii\base\Object
} else {
$this->where = array('and', $this->where, $condition);
}
if (!is_array($params)) {
$params = func_get_args();
unset($params[0]);
}
$this->addParams($params);
return $this;
}
@ -533,7 +509,6 @@ class Query extends \yii\base\Object
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
* @see where()
* @see andWhere()
@ -545,109 +520,78 @@ class Query extends \yii\base\Object
} else {
$this->where = array('or', $this->where, $condition);
}
if (!is_array($params)) {
$params = func_get_args();
unset($params[0]);
}
$this->addParams($params);
return $this;
}
/**
* Appends an INNER JOIN part to the query.
* Appends a JOIN part to the query.
* The first parameter specifies what type of join it is.
* @param string $type the type of join, such as INNER JOIN, LEFT JOIN.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $condition the join condition that should appear in the ON part.
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
*/
public function join($table, $condition, $params = array())
public function join($type, $table, $on = '', $params = array())
{
$this->join[] = array('JOIN', $table, $condition);
if (!is_array($params)) {
$params = func_get_args();
array_shift($params);
unset($params[0]);
}
$this->join[] = array($type, $table, $on);
return $this->addParams($params);
}
/**
* Appends a LEFT OUTER JOIN part to the query.
* Appends an INNER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $condition the join condition that should appear in the ON part.
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
*/
public function leftJoin($table, $condition, $params = array())
public function innerJoin($table, $on = '', $params = array())
{
$this->join[] = array('LEFT JOIN', $table, $condition);
if (!is_array($params)) {
$params = func_get_args();
array_shift($params);
unset($params[0]);
}
$this->join[] = array('INNER JOIN', $table, $on);
return $this->addParams($params);
}
/**
* Appends a RIGHT OUTER JOIN part to the query.
* Appends a LEFT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $condition the join condition that should appear in the ON part.
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Query the query object itself
*/
public function rightJoin($table, $condition, $params = array())
public function leftJoin($table, $on = '', $params = array())
{
$this->join[] = array('RIGHT JOIN', $table, $condition);
if (!is_array($params)) {
$params = func_get_args();
array_shift($params);
unset($params[0]);
}
$this->join[] = array('LEFT JOIN', $table, $on);
return $this->addParams($params);
}
/**
* Appends a CROSS JOIN part to the query.
* Note that not all DBMS support CROSS JOIN.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @return Query the query object itself
*/
public function crossJoin($table)
{
$this->join[] = array('CROSS JOIN', $table);
return $this;
}
/**
* Appends a NATURAL JOIN part to the query.
* Note that not all DBMS support NATURAL JOIN.
* Appends a RIGHT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Query the query object itself
*/
public function naturalJoin($table)
public function rightJoin($table, $on = '', $params = array())
{
$this->join[] = array('NATURAL JOIN', $table);
return $this;
$this->join[] = array('RIGHT JOIN', $table, $on);
return $this->addParams($params);
}
/**
@ -695,7 +639,6 @@ class Query extends \yii\base\Object
* @param string|array $condition the conditions to be put after HAVING.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
* @see andHaving()
* @see orHaving()
@ -703,10 +646,6 @@ class Query extends \yii\base\Object
public function having($condition, $params = array())
{
$this->having = $condition;
if (!is_array($params)) {
$params = func_get_args();
unset($params[0]);
}
$this->addParams($params);
return $this;
}
@ -717,7 +656,6 @@ class Query extends \yii\base\Object
* @param string|array $condition the new HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
* @see having()
* @see orHaving()
@ -729,10 +667,6 @@ class Query extends \yii\base\Object
} else {
$this->having = array('and', $this->having, $condition);
}
if (!is_array($params)) {
$params = func_get_args();
unset($params[0]);
}
$this->addParams($params);
return $this;
}
@ -743,7 +677,6 @@ class Query extends \yii\base\Object
* @param string|array $condition the new HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
* @see having()
* @see andHaving()
@ -755,10 +688,6 @@ class Query extends \yii\base\Object
} else {
$this->having = array('or', $this->having, $condition);
}
if (!is_array($params)) {
$params = func_get_args();
unset($params[0]);
}
$this->addParams($params);
return $this;
}
@ -840,7 +769,6 @@ class Query extends \yii\base\Object
* Sets the parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
* @see addParams()
*/
@ -854,7 +782,6 @@ class Query extends \yii\base\Object
* Adds additional parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Query the query object itself
* @see params()
*/

9
framework/db/dao/QueryBuilder.php

@ -488,7 +488,7 @@ class QueryBuilder extends \yii\base\Object
);
if (!is_array($condition)) {
return $condition;
return (string)$condition;
} elseif ($condition === array()) {
return '';
}
@ -733,8 +733,11 @@ class QueryBuilder extends \yii\base\Object
}
}
$joins[$i] = strtoupper($join[0]) . ' ' . $table;
if (isset($join[2])) { // join condition
$joins[$i] .= ' ON ' . $this->buildCondition($join[2]);
if (isset($join[2])) {
$condition = $this->buildCondition($join[2]);
if ($condition !== '') {
$joins[$i] .= ' ON ' . $this->buildCondition($join[2]);
}
}
} else {
throw new Exception('A join clause must be specified as an array of at least two elements.');

12
tests/unit/framework/db/ar/ActiveRecordTest.php

@ -63,7 +63,8 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$pk = array('order_id' => 2, 'item_id' => 4);
$orderItem = OrderItem::find($pk)->one();
$this->assertEquals(1, $orderItem->quantity);
$orderItem->saveCounters(array('quantity' => -1));
$ret = $orderItem->saveCounters(array('quantity' => -1));
$this->assertTrue($ret);
$this->assertEquals(0, $orderItem->quantity);
$orderItem = OrderItem::find($pk)->one();
$this->assertEquals(0, $orderItem->quantity);
@ -71,9 +72,10 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
// updateAll
$customer = Customer::find(3)->one();
$this->assertEquals('user3', $customer->name);
Customer::updateAll(array(
$ret = Customer::updateAll(array(
'name' => 'temp',
), array('id' => 3));
$this->assertEquals(1, $ret);
$customer = Customer::find(3)->one();
$this->assertEquals('temp', $customer->name);
@ -81,9 +83,10 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$pk = array('order_id' => 1, 'item_id' => 2);
$orderItem = OrderItem::find($pk)->one();
$this->assertEquals(2, $orderItem->quantity);
OrderItem::updateCounters(array(
$ret = OrderItem::updateCounters(array(
'quantity' => 3,
), $pk);
$this->assertEquals(1, $ret);
$orderItem = OrderItem::find($pk)->one();
$this->assertEquals(5, $orderItem->quantity);
}
@ -101,7 +104,8 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
// deleteAll
$customers = Customer::find()->all();
$this->assertEquals(2, count($customers));
Customer::deleteAll();
$ret = Customer::deleteAll();
$this->assertEquals(2, $ret);
$customers = Customer::find()->all();
$this->assertEquals(0, count($customers));
}

Loading…
Cancel
Save