Commit e3d57f0c by Qiang Xue

Merge branch 'console-color'

parents 0bdceee0 328bb2c0
...@@ -68,11 +68,10 @@ abstract class ActiveRecord extends Model ...@@ -68,11 +68,10 @@ abstract class ActiveRecord extends Model
public static function model() public static function model()
{ {
$className = get_called_class(); $className = get_called_class();
if (isset(self::$_models[$className])) { if (!isset(self::$_models[$className])) {
return self::$_models[$className]; self::$_models[$className] = new static;
} else {
return self::$_models[$className] = new static;
} }
return self::$_models[$className];
} }
/** /**
...@@ -252,7 +251,7 @@ abstract class ActiveRecord extends Model ...@@ -252,7 +251,7 @@ abstract class ActiveRecord extends Model
*/ */
public static function createActiveQuery() public static function createActiveQuery()
{ {
return new ActiveQuery(get_called_class()); return new ActiveQuery(array('modelClass' => get_called_class()));
} }
/** /**
...@@ -382,6 +381,38 @@ abstract class ActiveRecord extends Model ...@@ -382,6 +381,38 @@ abstract class ActiveRecord extends Model
} }
} }
public function hasOne($class, $link)
{
return new HasOneRelation(array(
'modelClass' => $class,
'parentClass' => get_class($this),
'parentRecords' => array($this),
'link' => $link,
));
}
public function hasMany($class, $link)
{
return new HasManyRelation(array(
'modelClass' => $class,
'parentClass' => get_class($this),
'parentRecords' => array($this),
'link' => $link,
));
}
public function manyMany($class, $leftLink, $joinTable, $rightLink)
{
return new ManyManyRelation(array(
'modelClass' => $class,
'parentClass' => get_class($this),
'parentRecords' => array($this),
'leftLink' => $leftLink,
'joinTable' => $joinTable,
'rightLink' => $rightLink,
));
}
/** /**
* Initializes the internal storage for the relation. * Initializes the internal storage for the relation.
* This method is internally used by [[ActiveQuery]] when populating relation data. * This method is internally used by [[ActiveQuery]] when populating relation data.
......
<?php
namespace yii\db\ar;
class HasManyRelation extends Relation
{
public $link;
}
<?php
namespace yii\db\ar;
class HasOneRelation extends Relation
{
public $link;
}
<?php
namespace yii\db\ar;
class ManyManyRelation extends Relation
{
public $joinTable;
public $leftLink;
public $rightLink;
}
<?php
namespace yii\db\ar;
class Relation extends ActiveQuery
{
public $parentClass;
public function findWith(&$parentRecords)
{
$this->andWhere(array('in', $links, $keys));
$records = $this->find();
foreach ($records as $record) {
// find the matching parent record(s)
// insert into the parent records(s)
}
}
}
...@@ -532,103 +532,23 @@ class BaseQuery extends \yii\base\Component ...@@ -532,103 +532,23 @@ class BaseQuery extends \yii\base\Component
/** /**
* Merges this query with another one. * Merges this query with another one.
* * If a property of `$query` is not null, it will be used to overwrite
* The merging is done according to the following rules: * the corresponding property of `$this`.
*
* - [[select]]: the union of both queries' [[select]] property values.
* - [[selectOption]], [[distinct]], [[from]], [[limit]], [[offset]]: the new query
* takes precedence over this query.
* - [[where]], [[having]]: the new query's corresponding property value
* will be 'AND' together with the existing one.
* - [[params]], [[orderBy]], [[groupBy]], [[join]], [[union]]: the new query's
* corresponding property value will be appended to the existing one.
*
* In general, the merging makes the resulting query more restrictive and specific.
* @param BaseQuery $query the new query to be merged with this query. * @param BaseQuery $query the new query to be merged with this query.
* @return BaseQuery the query object itself * @return BaseQuery the query object itself
*/ */
public function mergeWith(BaseQuery $query) public function mergeWith(BaseQuery $query)
{ {
if ($this->select !== $query->select) { $properties = array(
if (empty($this->select)) { 'select', 'selectOption', 'distinct', 'from',
$this->select = $query->select; 'where', 'limit', 'offset', 'orderBy', 'groupBy',
} elseif (!empty($query->select)) { 'join', 'having', 'union', 'params',
$select1 = is_string($this->select) ? preg_split('/\s*,\s*/', trim($this->select), -1, PREG_SPLIT_NO_EMPTY) : $this->select; );
$select2 = is_string($query->select) ? preg_split('/\s*,\s*/', trim($query->select), -1, PREG_SPLIT_NO_EMPTY) : $query->select; foreach ($properties as $name => $value) {
$this->select = array_merge($select1, array_diff($select2, $select1)); if ($value !== null) {
} $this->$name = $value;
}
if ($query->selectOption !== null) {
$this->selectOption = $query->selectOption;
}
if ($query->distinct !== null) {
$this->distinct = $query->distinct;
}
if ($query->from !== null) {
$this->from = $query->from;
}
if ($query->limit !== null) {
$this->limit = $query->limit;
}
if ($query->offset !== null) {
$this->offset = $query->offset;
}
if ($query->where !== null) {
$this->andWhere($query->where);
}
if ($query->having !== null) {
$this->andHaving($query->having);
}
if ($query->params !== null) {
$this->addParams($query->params);
}
if ($query->orderBy !== null) {
$this->addOrderBy($query->orderBy);
}
if ($query->groupBy !== null) {
$this->addGroup($query->groupBy);
}
if ($query->join !== null) {
if (empty($this->join)) {
$this->join = $query->join;
} else {
if (!is_array($this->join)) {
$this->join = array($this->join);
}
if (is_array($query->join)) {
$this->join = array_merge($this->join, $query->join);
} else {
$this->join[] = $query->join;
}
} }
} }
if ($query->union !== null) {
if (empty($this->union)) {
$this->union = $query->union;
} else {
if (!is_array($this->union)) {
$this->union = array($this->union);
}
if (is_array($query->union)) {
$this->union = array_merge($this->union, $query->union);
} else {
$this->union[] = $query->union;
}
}
}
return $this; return $this;
} }
} }
...@@ -469,16 +469,16 @@ class QueryBuilder extends \yii\base\Object ...@@ -469,16 +469,16 @@ class QueryBuilder extends \yii\base\Object
public function buildCondition($condition) public function buildCondition($condition)
{ {
static $builders = array( static $builders = array(
'and' => 'buildAndCondition', 'AND' => 'buildAndCondition',
'or' => 'buildAndCondition', 'OR' => 'buildAndCondition',
'between' => 'buildBetweenCondition', 'BETWEEN' => 'buildBetweenCondition',
'not between' => 'buildBetweenCondition', 'NOT BETWEEN' => 'buildBetweenCondition',
'in' => 'buildInCondition', 'IN' => 'buildInCondition',
'not in' => 'buildInCondition', 'NOT IN' => 'buildInCondition',
'like' => 'buildLikeCondition', 'LIKE' => 'buildLikeCondition',
'not like' => 'buildLikeCondition', 'NOT LIKE' => 'buildLikeCondition',
'or like' => 'buildLikeCondition', 'OR LIKE' => 'buildLikeCondition',
'or not like' => 'buildLikeCondition', 'OR NOT LIKE' => 'buildLikeCondition',
); );
if (!is_array($condition)) { if (!is_array($condition)) {
...@@ -487,7 +487,7 @@ class QueryBuilder extends \yii\base\Object ...@@ -487,7 +487,7 @@ class QueryBuilder extends \yii\base\Object
return ''; return '';
} }
if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ... if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ...
$operator = $condition[0]; $operator = strtoupper($condition[0]);
if (isset($builders[$operator])) { if (isset($builders[$operator])) {
$method = $builders[$operator]; $method = $builders[$operator];
array_shift($condition); array_shift($condition);
...@@ -534,7 +534,6 @@ class QueryBuilder extends \yii\base\Object ...@@ -534,7 +534,6 @@ class QueryBuilder extends \yii\base\Object
} }
} }
if ($parts !== array()) { if ($parts !== array()) {
$operator = strtoupper($operator);
return '(' . implode(") $operator (", $parts) . ')'; return '(' . implode(") $operator (", $parts) . ')';
} else { } else {
return ''; return '';
...@@ -568,22 +567,62 @@ class QueryBuilder extends \yii\base\Object ...@@ -568,22 +567,62 @@ class QueryBuilder extends \yii\base\Object
$values = (array)$values; $values = (array)$values;
if ($values === array()) { if ($values === array() || $column === array()) {
return $operator === 'in' ? '0=1' : ''; return $operator === 'in' ? '0=1' : '';
} }
if (is_array($column)) {
if (count($column) > 1) {
return $this->buildCompositeInCondition($operator, $column, $values);
} else {
$column = reset($column);
foreach ($values as $i => $value) {
if (is_array($value)) {
$values[$i] = isset($value[$column]) ? $value[$column] : null;
} else {
$values[$i] = null;
}
}
}
}
foreach ($values as $i => $value) { foreach ($values as $i => $value) {
$values[$i] = is_string($value) ? $this->connection->quoteValue($value) : (string)$value; if ($value === null) {
$values[$i] = 'NULL';
} else {
$values[$i] = is_string($value) ? $this->connection->quoteValue($value) : (string)$value;
}
} }
if (strpos($column, '(') === false) { if (strpos($column, '(') === false) {
$column = $this->quoteColumnName($column); $column = $this->quoteColumnName($column);
} }
$operator = strtoupper($operator);
return "$column $operator (" . implode(', ', $values) . ')'; return "$column $operator (" . implode(', ', $values) . ')';
} }
protected function buildCompositeInCondition($operator, $columns, $values)
{
foreach ($columns as $i => $column) {
if (strpos($column, '(') === false) {
$columns[$i] = $this->quoteColumnName($column);
}
}
$vss = array();
foreach ($values as $value) {
$vs = array();
foreach ($columns as $column) {
if (isset($value[$column])) {
$vs[] = is_string($value[$column]) ? $this->connection->quoteValue($value[$column]) : (string)$value[$column];
} else {
$vs[] = 'NULL';
}
}
$vss[] = '(' . implode(', ', $vs) . ')';
}
return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')';
}
private function buildLikeCondition($operator, $operands) private function buildLikeCondition($operator, $operands)
{ {
if (!isset($operands[0], $operands[1])) { if (!isset($operands[0], $operands[1])) {
...@@ -595,21 +634,20 @@ class QueryBuilder extends \yii\base\Object ...@@ -595,21 +634,20 @@ class QueryBuilder extends \yii\base\Object
$values = (array)$values; $values = (array)$values;
if ($values === array()) { if ($values === array()) {
return $operator === 'like' || $operator === 'or like' ? '0=1' : ''; return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0=1' : '';
} }
if ($operator === 'like' || $operator === 'not like') { if ($operator === 'LIKE' || $operator === 'NOT LIKE') {
$andor = ' AND '; $andor = ' AND ';
} else { } else {
$andor = ' OR '; $andor = ' OR ';
$operator = $operator === 'or like' ? 'like' : 'not like'; $operator = $operator === 'OR LIKE' ? 'LIKE' : 'NOT LIKE';
} }
if (strpos($column, '(') === false) { if (strpos($column, '(') === false) {
$column = $this->quoteColumnName($column); $column = $this->quoteColumnName($column);
} }
$operator = strtoupper($operator);
$parts = array(); $parts = array();
foreach ($values as $value) { foreach ($values as $value) {
$parts[] = "$column $operator " . $this->connection->quoteValue($value); $parts[] = "$column $operator " . $this->connection->quoteValue($value);
...@@ -726,7 +764,7 @@ class QueryBuilder extends \yii\base\Object ...@@ -726,7 +764,7 @@ class QueryBuilder extends \yii\base\Object
$table = $driver->quoteTableName($table); $table = $driver->quoteTableName($table);
} }
} }
$joins[$i] = strtoupper($join[0]) . ' ' . $table; $joins[$i] = $join[0] . ' ' . $table;
if (isset($join[2])) { if (isset($join[2])) {
$condition = $this->buildCondition($join[2]); $condition = $this->buildCondition($join[2]);
if ($condition !== '') { if ($condition !== '') {
......
...@@ -23,42 +23,14 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase ...@@ -23,42 +23,14 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$this->assertTrue($result instanceof ActiveQuery); $this->assertTrue($result instanceof ActiveQuery);
$customer = $result->one(); $customer = $result->one();
$this->assertTrue($customer instanceof Customer); $this->assertTrue($customer instanceof Customer);
$this->assertEquals(1, $result->count);
$this->assertEquals(1, count($result));
// find all // find all
$result = Customer::find(); $result = Customer::find();
$customers = $result->all(); $customers = $result->all();
$this->assertTrue(is_array($customers));
$this->assertEquals(3, count($customers)); $this->assertEquals(3, count($customers));
$this->assertTrue($customers[0] instanceof Customer); $this->assertTrue($customers[0] instanceof Customer);
$this->assertTrue($customers[1] instanceof Customer); $this->assertTrue($customers[1] instanceof Customer);
$this->assertTrue($customers[2] instanceof Customer); $this->assertTrue($customers[2] instanceof Customer);
$this->assertEquals(3, $result->count);
$this->assertEquals(3, count($result));
// check count first
$result = Customer::find();
$this->assertEquals(3, $result->count);
$customer = $result->one();
$this->assertTrue($customer instanceof Customer);
$this->assertEquals(3, $result->count);
// iterator
$result = Customer::find();
$count = 0;
foreach ($result as $customer) {
$this->assertTrue($customer instanceof Customer);
$count++;
}
$this->assertEquals($count, $result->count);
// array access
$result = Customer::find();
$this->assertTrue($result[0] instanceof Customer);
$this->assertTrue($result[1] instanceof Customer);
$this->assertTrue($result[2] instanceof Customer);
$this->assertEquals(3, count($result));
// find by a single primary key // find by a single primary key
$customer = Customer::find(2); $customer = Customer::find(2);
...@@ -70,7 +42,7 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase ...@@ -70,7 +42,7 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$this->assertTrue($customer instanceof Customer); $this->assertTrue($customer instanceof Customer);
$this->assertEquals(2, $customer->id); $this->assertEquals(2, $customer->id);
// find by Query // find by Query array
$query = array( $query = array(
'where' => 'id=:id', 'where' => 'id=:id',
'params' => array(':id' => 2), 'params' => array(':id' => 2),
...@@ -80,13 +52,59 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase ...@@ -80,13 +52,59 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$this->assertEquals('user2', $customer->name); $this->assertEquals('user2', $customer->name);
// find count // find count
$this->assertEquals(3, Customer::find()->count()); // $this->assertEquals(3, Customer::count());
$this->assertEquals(3, Customer::count()); // $this->assertEquals(2, Customer::count(array(
$this->assertEquals(2, Customer::count(array( // 'where' => 'id=1 OR id=2',
'where' => 'id=1 OR id=2', // )));
))); // $this->assertEquals(2, Customer::find()->select('COUNT(*)')->where('id=1 OR id=2')->value());
$this->assertEquals(2, Customer::count()->where('id=1 OR id=2')); }
public function testFindBySql()
{
// find one
$customer = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC')->one();
$this->assertTrue($customer instanceof Customer);
$this->assertEquals('user3', $customer->name);
// find all
$customers = Customer::findBySql('SELECT * FROM tbl_customer')->all();
$this->assertEquals(3, count($customers));
// find with parameter binding
$customer = Customer::findBySql('SELECT * FROM tbl_customer WHERE id=:id', array(':id' => 2))->one();
$this->assertTrue($customer instanceof Customer);
$this->assertEquals('user2', $customer->name);
}
public function testScope()
{
$customers = Customer::find(array(
'scopes' => array('active'),
))->all();
$this->assertEquals(2, count($customers));
$customers = Customer::find()->active()->all();
$this->assertEquals(2, count($customers));
} }
//
// public function testFindLazy()
// {
// $customer = Customer::find(2);
// $orders = $customer->orders;
// $this->assertEquals(2, count($orders));
//
// $orders = $customer->orders()->where('id=3')->all();
// $this->assertEquals(1, count($orders));
// $this->assertEquals(3, $orders[0]->id);
// }
//
// public function testFindEager()
// {
// $customers = Customer::find()->with('orders')->all();
// $this->assertEquals(3, count($customers));
// $this->assertEquals(1, count($customers[0]->orders));
// $this->assertEquals(2, count($customers[1]->orders));
// }
// public function testInsert() // public function testInsert()
// { // {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment