From a7ecbfee30f4abb1113576b8e042967f737af067 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 4 Jan 2013 15:06:19 -0500 Subject: [PATCH] Fixing AR issues. --- framework/db/ar/ActiveQuery.php | 13 ++++- framework/db/ar/ActiveRecord.php | 22 +++++--- framework/db/ar/ActiveRelation.php | 36 ++++++------ framework/db/dao/Command.php | 2 +- framework/db/dao/QueryBuilder.php | 9 ++- tests/unit/framework/db/ar/ActiveRecordTest.php | 75 +++++++++++++++++-------- 6 files changed, 103 insertions(+), 54 deletions(-) diff --git a/framework/db/ar/ActiveQuery.php b/framework/db/ar/ActiveQuery.php index 0490c46..cdfb745 100644 --- a/framework/db/ar/ActiveQuery.php +++ b/framework/db/ar/ActiveQuery.php @@ -214,6 +214,11 @@ class ActiveQuery extends BaseQuery // todo: normalize $relations $primaryModel = new $this->modelClass; foreach ($relations as $name => $properties) { + if (is_integer($name)) { + $name = $properties; + $properties = array(); + } + if (!method_exists($primaryModel, $name)) { throw new Exception("Unknown relation: $name"); } @@ -227,7 +232,13 @@ class ActiveQuery extends BaseQuery // inherit asArray from primary query $relation->asArray = $this->asArray; } - $relation->findWith($name, $models); + if ($relation->via !== null) { + $viaName = $relation->via; + $viaQuery = $primaryModel->$viaName(); + $relation->findWith($name, $models, $viaQuery); + } else { + $relation->findWith($name, $models); + } } } } diff --git a/framework/db/ar/ActiveRecord.php b/framework/db/ar/ActiveRecord.php index 3aa4478..f5a45b2 100644 --- a/framework/db/ar/ActiveRecord.php +++ b/framework/db/ar/ActiveRecord.php @@ -172,7 +172,8 @@ abstract class ActiveRecord extends Model } } elseif ($q !== null) { $query->select = array($q); - } elseif ($query->select === null) { + } + if ($query->select === null) { $query->select = array('COUNT(*)'); } return $query; @@ -300,7 +301,7 @@ abstract class ActiveRecord extends Model return null; } elseif (method_exists($this, $name)) { // related records - if (isset($this->_related[$name]) || array_key_exists($name, $this->_related)) { + if (isset($this->_related[$name]) || isset($this->_related) && array_key_exists($name, $this->_related)) { return $this->_related[$name]; } else { // lazy loading related records @@ -379,8 +380,15 @@ abstract class ActiveRecord extends Model */ public function hasOne($class, $link, $properties = array()) { - $properties['primaryModel'] = $this; + if (strpos($class, '\\') === false) { + $primaryClass = get_class($this); + if (strpos($primaryClass, '\\') !== false) { + $class = dirname($primaryClass) . '\\' . $class; + } + } + $properties['modelClass'] = $class; + $properties['primaryModel'] = $this; $properties['link'] = $link; $properties['multiple'] = false; return new ActiveRelation($properties); @@ -400,11 +408,9 @@ abstract class ActiveRecord extends Model */ public function hasMany($class, $link, $properties = array()) { - $properties['primaryModel'] = $this; - $properties['modelClass'] = $class; - $properties['link'] = $link; - $properties['multiple'] = true; - return new ActiveRelation($properties); + $relation = $this->hasOne($class, $link, $properties); + $relation->multiple = true; + return $relation; } /** diff --git a/framework/db/ar/ActiveRelation.php b/framework/db/ar/ActiveRelation.php index c7fcc13..f6e7f2e 100644 --- a/framework/db/ar/ActiveRelation.php +++ b/framework/db/ar/ActiveRelation.php @@ -49,7 +49,7 @@ class ActiveRelation extends ActiveQuery public function via($modelClass, $properties = array()) { - $this->via = array($modelClass, $properties); + $this->via = $modelClass; return $this; } @@ -65,9 +65,12 @@ class ActiveRelation extends ActiveQuery if ($this->via !== null) { /** @var $viaQuery ActiveRelation */ $viaName = $this->via; - $viaQuery = $this->$viaName(); - $primaryModels = array($this->primaryModel); - $viaModels = $viaQuery->findWith($viaName, $primaryModels); + $viaModels = $this->primaryModel->$viaName; + if ($viaModels === null) { + $viaModels = array(); + } elseif (!is_array($viaModels)) { + $viaModels = array($viaModels); + } $this->filterByModels($viaModels); } else { $this->filterByModels(array($this->primaryModel)); @@ -76,17 +79,14 @@ class ActiveRelation extends ActiveQuery return parent::createCommand(); } - public function findWith($name, &$primaryModels) + public function findWith($name, &$primaryModels, $viaQuery = null) { if (!is_array($this->link)) { throw new \yii\base\Exception('invalid link'); } - if ($this->via !== null) { - /** @var $viaQuery ActiveRelation */ - $viaName = $this->via; - $viaQuery = $this->$viaName(); - $viaModels = $viaQuery->findWith($viaName, $primaryModels); + if ($viaQuery !== null) { + $viaModels = $viaQuery->findWith($this->via, $primaryModels); $this->filterByModels($viaModels); } else { $this->filterByModels($primaryModels); @@ -178,21 +178,21 @@ class ActiveRelation extends ActiveQuery { $attributes = array_keys($this->link); $values = array(); - if (isset($links[1])) { + if (count($attributes) ===1) { + // single key + $attribute = reset($this->link); + foreach ($models as $model) { + $values[] = $model[$attribute]; + } + } else { // composite keys foreach ($models as $model) { $v = array(); foreach ($this->link as $attribute => $link) { - $v[$attribute] = is_array($model) ? $model[$link] : $model->$link; + $v[$attribute] = $model[$link]; } $values[] = $v; } - } else { - // single key - $attribute = $this->link[$links[0]]; - foreach ($models as $model) { - $values[] = is_array($model) ? $model[$attribute] : $model->$attribute; - } } $this->andWhere(array('in', $attributes, $values)); } diff --git a/framework/db/dao/Command.php b/framework/db/dao/Command.php index bde3225..78b3581 100644 --- a/framework/db/dao/Command.php +++ b/framework/db/dao/Command.php @@ -365,7 +365,7 @@ class Command extends \yii\base\Component } \Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__); - +echo $sql."\n\n"; if ($db->queryCachingCount > 0 && $db->queryCachingDuration >= 0 && $method !== '') { $cache = \Yii::$application->getComponent($db->queryCacheID); } diff --git a/framework/db/dao/QueryBuilder.php b/framework/db/dao/QueryBuilder.php index fad17fe..259c266 100644 --- a/framework/db/dao/QueryBuilder.php +++ b/framework/db/dao/QueryBuilder.php @@ -568,7 +568,7 @@ class QueryBuilder extends \yii\base\Object $values = (array)$values; if ($values === array() || $column === array()) { - return $operator === 'in' ? '0=1' : ''; + return $operator === 'IN' ? '0=1' : ''; } if (is_array($column)) { @@ -593,7 +593,12 @@ class QueryBuilder extends \yii\base\Object $column = $this->quoteColumnName($column); } - return "$column $operator (" . implode(', ', $values) . ')'; + if (count($values) > 1) { + return "$column $operator (" . implode(', ', $values) . ')'; + } else { + $operator = $operator === 'IN' ? '=' : '<>'; + return "$column$operator{$values[0]}"; + } } protected function buildCompositeInCondition($operator, $columns, $values) diff --git a/tests/unit/framework/db/ar/ActiveRecordTest.php b/tests/unit/framework/db/ar/ActiveRecordTest.php index 923345b..86a1bd1 100644 --- a/tests/unit/framework/db/ar/ActiveRecordTest.php +++ b/tests/unit/framework/db/ar/ActiveRecordTest.php @@ -52,11 +52,11 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase $this->assertEquals('user2', $customer->name); // find count -// $this->assertEquals(3, Customer::count()); -// $this->assertEquals(2, Customer::count(array( -// 'where' => 'id=1 OR id=2', -// ))); -// $this->assertEquals(2, Customer::find()->select('COUNT(*)')->where('id=1 OR id=2')->value()); + $this->assertEquals(3, Customer::count()->value()); + $this->assertEquals(2, Customer::count(array( + 'where' => 'id=1 OR id=2', + ))->value()); + $this->assertEquals(2, Customer::find()->select('COUNT(*)')->where('id=1 OR id=2')->value()); } public function testFindBySql() @@ -86,25 +86,52 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase $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 testFindLazy() + { + /** @var $customer Customer */ + $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 testFindLazyVia() + { + /** @var $order Order */ + $order = Order::find(1); + $this->assertEquals(1, $order->id); + $this->assertEquals(2, count($order->items)); + $this->assertEquals(1, $order->items[0]->id); + $this->assertEquals(2, $order->items[1]->id); + + $order = Order::find(1); + $order->id = 100; + $this->assertEquals(array(), $order->items); + } + + public function testFindEagerVia() + { + $orders = Order::find()->with('items')->orderBy('id')->all(); + $this->assertEquals(3, count($orders)); + $order = $orders[0]; + $this->assertEquals(1, $order->id); + $this->assertEquals(2, count($order->items)); + $this->assertEquals(1, $order->items[0]->id); + $this->assertEquals(2, $order->items[1]->id); + } + // public function testInsert() // {