From c5cdcab6c6f3c63be041f0b7f516298cc058ab07 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 Feb 2012 16:22:42 -0500 Subject: [PATCH] ... --- framework/db/ar/ActiveMetaData.php | 14 +- framework/db/ar/ActiveQuery.php | 98 +++++++++++--- framework/db/ar/ActiveRecord.php | 165 +++++++++--------------- framework/db/ar/JoinElement.php | 93 +++++++++---- framework/db/dao/QueryBuilder.php | 2 +- tests/unit/data/ar/Customer.php | 9 ++ tests/unit/data/ar/Order.php | 9 ++ tests/unit/data/mysql.sql | 2 +- tests/unit/framework/db/ar/ActiveRecordTest.php | 12 ++ 9 files changed, 250 insertions(+), 154 deletions(-) diff --git a/framework/db/ar/ActiveMetaData.php b/framework/db/ar/ActiveMetaData.php index 9c3f63f..9728ed9 100644 --- a/framework/db/ar/ActiveMetaData.php +++ b/framework/db/ar/ActiveMetaData.php @@ -18,6 +18,10 @@ class ActiveMetaData */ public $table; /** + * @var string the model class name + */ + public $modelClass; + /** * @var array list of relations */ public $relations = array(); @@ -30,6 +34,7 @@ class ActiveMetaData { $tableName = $modelClass::tableName(); $this->table = $modelClass::getDbConnection()->getDriver()->getTableSchema($tableName); + $this->modelClass = $modelClass; if ($this->table === null) { throw new Exception("Unable to find table '$tableName' for ActiveRecord class '$modelClass'."); } @@ -64,11 +69,16 @@ class ActiveMetaData } $relation = ActiveRelation::newInstance($config); $relation->name = $matches[1]; - $relation->modelClass = '\\' . $matches[2]; + $modelClass = $matches[2]; + if (strpos($modelClass, '\\') !== false) { + $relation->modelClass = '\\' . ltrim($modelClass, '\\'); + } else { + $relation->modelClass = dirname($this->modelClass) . '\\' . $modelClass; + } $relation->hasMany = isset($matches[3]); $this->relations[$relation->name] = $relation; } else { - throw new Exception("Relation name in bad format: $name"); + throw new Exception("{$this->modelClass} has an invalid relation: $name"); } } } \ No newline at end of file diff --git a/framework/db/ar/ActiveQuery.php b/framework/db/ar/ActiveQuery.php index f6e2a07..ae90b2a 100644 --- a/framework/db/ar/ActiveQuery.php +++ b/framework/db/ar/ActiveQuery.php @@ -18,6 +18,18 @@ use yii\db\Exception; * ActiveFinder.php is ... * todo: add SQL monitor * + * todo: add ActiveQueryBuilder + * todo: quote join/on part of the relational query + * todo: modify QueryBuilder about join() methods + * todo: unify ActiveQuery and ActiveRelation in query building process + * todo: intelligent table aliasing (first table name, then relation name, finally t?) + * todo: allow using tokens in primary query fragments + * todo: findBySql + * todo: base limited + * todo: lazy loading + * todo: scope + * todo: test via option + * * @author Qiang Xue * @since 2.0 */ @@ -692,7 +704,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array { if (!empty($this->with)) { // todo: handle findBySql() and limit cases - $this->initRelationalQuery(); + $joinTree = $this->buildRelationalQuery(); } if ($this->sql === null) { @@ -703,9 +715,16 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array $command = $this->getDbConnection()->createCommand($this->sql); $command->bindValues($this->query->params); } - +echo $command->sql; $rows = $command->queryAll(); + if (!empty($this->with)) { + foreach ($rows as $row) { + $joinTree->populateData($row); + } + return array_values($joinTree->records); + } + if ($this->asArray) { if ($this->indexBy === null) { return $rows; @@ -759,45 +778,76 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array } } - protected function initRelationalQuery() + protected function buildRelationalQuery() { - $joinTree = new JoinElement(null, null); - $joinCount = 0; - $this->buildJoinTree($joinTree, $this->with, $joinCount); + $joinTree = new JoinElement($this, null, null); + $this->buildJoinTree($joinTree, $this->with); + $this->buildTableAlias($joinTree); $query = new Query; foreach ($joinTree->children as $child) { $child->buildQuery($query); } + + $select = $joinTree->buildSelect($this->query->select); + if (!empty($query->select)) { + $this->query->select = array_merge($select, $query->select); + } else { + $this->query->select = $select; + } + if (!empty($query->where)) { + $this->query->andWhere('(' . implode(') AND (', $query->where) . ')'); + } + if (!empty($query->having)) { + $this->query->andHaving('(' . implode(') AND (', $query->having) . ')'); + } + if (!empty($query->join)) { + if ($this->query->join === null) { + $this->query->join = $query->join; + } else { + $this->query->join = array_merge($this->query->join, $query->join); + } + } + if (!empty($query->orderBy)) { + $this->query->addOrderBy($query->orderBy); + } + if (!empty($query->groupBy)) { + $this->query->addGroupBy($query->groupBy); + } + if (!empty($query->params)) { + $this->query->addParams($query->params); + } + + return $joinTree; } /** * @param JoinElement $parent * @param array|string $with - * @param integer $joinCount * @param array $config * @return null|JoinElement * @throws \yii\db\Exception */ - protected function buildJoinTree($parent, $with, &$joinCount, $config = array()) + protected function buildJoinTree($parent, $with, $config = array()) { if (is_array($with)) { foreach ($with as $name => $value) { if (is_string($value)) { - $this->buildJoinTree($parent, $value, $joinCount); + $this->buildJoinTree($parent, $value); } elseif (is_string($name) && is_array($value)) { - $this->buildJoinTree($parent, $name, $joinCount, $value); + $this->buildJoinTree($parent, $name, $value); } } return null; } if (($pos = strrpos($with, '.')) !== false) { - $parent = $this->buildJoinTree($parent, substr($with, 0, $pos), $joinCount); + $parent = $this->buildJoinTree($parent, substr($with, 0, $pos)); $with = substr($with, $pos + 1); } if (isset($parent->children[$with])) { $child = $parent->children[$with]; + $child->joinOnly = false; } else { $modelClass = $parent->relation->modelClass; $relations = $modelClass::getMetaData()->relations; @@ -805,20 +855,32 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array throw new Exception("$modelClass has no relation named '$with'."); } $relation = clone $relations[$with]; - if ($relation->tableAlias === null) { - $relation->tableAlias = 't' . ($joinCount++); + if ($relation->via !== null && isset($relations[$relation->via])) { + $relation->via = null; + $parent2 = $this->buildJoinTree($parent, $relation->via); + if ($parent2->joinOnly === null) { + $parent2->joinOnly = true; + } + $child = new JoinElement($relation, $parent2, $parent); + } else { + $child = new JoinElement($relation, $parent, $parent); } - $child = new JoinElement($parent, $relation); } foreach ($config as $name => $value) { $child->relation->$name = $value; } - if (!empty($child->relation->with)) { - $this->buildJoinTree($child, $child->relation->with, $joinCount); - } - return $child; } + + protected function buildTableAlias($element, &$count = 0) + { + if ($element->relation->tableAlias === null) { + $element->relation->tableAlias = 't' . ($count++); + } + foreach ($element->children as $child) { + $this->buildTableAlias($child, $count); + } + } } diff --git a/framework/db/ar/ActiveRecord.php b/framework/db/ar/ActiveRecord.php index 6a4fa87..041a328 100644 --- a/framework/db/ar/ActiveRecord.php +++ b/framework/db/ar/ActiveRecord.php @@ -167,15 +167,15 @@ abstract class ActiveRecord extends \yii\base\Model * * ~~~ * return array( - * 'manager:Manager' => '?.manager_id = manager.id', - * 'assignments:Assignment[]' => array( - * 'on' => '?.id = assignments.owner_id AND assignments.status=1', - * 'orderBy' => 'assignments.create_time DESC', - * ), - * 'projects:Project[]' => array( - * 'via' => 'assignments', - * 'on' => 'projects.id = assignments.project_id', - * ), + * 'manager:Manager' => '?.manager_id = manager.id', + * 'assignments:Assignment[]' => array( + * 'on' => '?.id = assignments.owner_id AND assignments.status=1', + * 'orderBy' => 'assignments.create_time DESC', + * ), + * 'projects:Project[]' => array( + * 'via' => 'assignments', + * 'on' => 'projects.id = assignments.project_id', + * ), * ); * ~~~ * @@ -373,21 +373,13 @@ abstract class ActiveRecord extends \yii\base\Model { if (isset($this->_attributes[$name])) { return true; - } - elseif (isset($this->getMetaData()->columns[$name])) - { + } elseif (isset($this->getMetaData()->columns[$name])) { return false; - } - elseif (isset($this->_related[$name])) - { + } elseif (isset($this->_related[$name])) { return true; - } - elseif (isset($this->getMetaData()->relations[$name])) - { + } elseif (isset($this->getMetaData()->relations[$name])) { return $this->getRelatedRecord($name) !== null; - } - else - { + } else { return parent::__isset($name); } } @@ -402,13 +394,9 @@ abstract class ActiveRecord extends \yii\base\Model { if (isset($this->getMetaData()->columns[$name])) { unset($this->_attributes[$name]); - } - elseif (isset($this->getMetaData()->relations[$name])) - { + } elseif (isset($this->getMetaData()->relations[$name])) { unset($this->_related[$name]); - } - else - { + } else { parent::__unset($name); } } @@ -426,9 +414,7 @@ abstract class ActiveRecord extends \yii\base\Model if (isset($this->getMetaData()->relations[$name])) { if (empty($parameters)) { return $this->getRelatedRecord($name, false); - } - else - { + } else { return $this->getRelatedRecord($name, false, $parameters[0]); } } @@ -442,6 +428,20 @@ abstract class ActiveRecord extends \yii\base\Model return parent::__call($name, $parameters); } + public function initRelatedRecord($relation) + { + $this->_related[$relation->name] = $relation->hasMany ? array() : null; + } + + public function addRelatedRecord($relation, $record) + { + if ($relation->hasMany) { + $this->_related[$relation->name][] = $record; + } else { + $this->_related[$relation->name] = $record; + } + } + /** * Returns the related record(s). * This method will return the related record(s) of the current record. @@ -464,8 +464,7 @@ abstract class ActiveRecord extends \yii\base\Model $md = $this->getMetaData(); if (!isset($md->relations[$name])) { - throw new Exception(Yii::t('yii', '{class} does not have relation "{name}".', - array('{class}' => get_class($this), '{name}' => $name))); + throw new Exception(Yii::t('yii', '{class} does not have relation "{name}".', array('{class}' => get_class($this), '{name}' => $name))); } Yii::trace('lazy loading ' . get_class($this) . '.' . $name, 'system.db.ar.ActiveRecord'); @@ -481,8 +480,7 @@ abstract class ActiveRecord extends \yii\base\Model $save = $this->_related[$name]; } $r = array($name => $params); - } else - { + } else { $r = $name; } unset($this->_related[$name]); @@ -493,13 +491,9 @@ abstract class ActiveRecord extends \yii\base\Model if (!isset($this->_related[$name])) { if ($relation instanceof CHasManyRelation) { $this->_related[$name] = array(); - } - elseif ($relation instanceof CStatRelation) - { + } elseif ($relation instanceof CStatRelation) { $this->_related[$name] = $relation->defaultValue; - } - else - { + } else { $this->_related[$name] = null; } } @@ -508,14 +502,11 @@ abstract class ActiveRecord extends \yii\base\Model $results = $this->_related[$name]; if ($exists) { $this->_related[$name] = $save; - } - else - { + } else { unset($this->_related[$name]); } return $results; - } else - { + } else { return $this->_related[$name]; } } @@ -617,9 +608,7 @@ abstract class ActiveRecord extends \yii\base\Model { if (property_exists($this, $name)) { return $this->$name; - } - elseif (isset($this->_attributes[$name])) - { + } elseif (isset($this->_attributes[$name])) { return $this->_attributes[$name]; } } @@ -636,13 +625,9 @@ abstract class ActiveRecord extends \yii\base\Model { if (property_exists($this, $name)) { $this->$name = $value; - } - elseif (isset($this->getMetaData()->table->columns[$name])) - { + } elseif (isset($this->getMetaData()->table->columns[$name])) { $this->_attributes[$name] = $value; - } - else - { + } else { return false; } return true; @@ -660,31 +645,24 @@ abstract class ActiveRecord extends \yii\base\Model public function getAttributes($names = true) { $attributes = $this->_attributes; - foreach ($this->getMetaData()->columns as $name => $column) - { + foreach ($this->getMetaData()->columns as $name => $column) { if (property_exists($this, $name)) { $attributes[$name] = $this->$name; - } - elseif ($names === true && !isset($attributes[$name])) - { + } elseif ($names === true && !isset($attributes[$name])) { $attributes[$name] = null; } } if (is_array($names)) { $attrs = array(); - foreach ($names as $name) - { + foreach ($names as $name) { if (property_exists($this, $name)) { $attrs[$name] = $this->$name; - } - else - { + } else { $attrs[$name] = isset($attributes[$name]) ? $attributes[$name] : null; } } return $attrs; - } else - { + } else { return $attributes; } } @@ -716,9 +694,7 @@ abstract class ActiveRecord extends \yii\base\Model { if (!$runValidation || $this->validate($attributes)) { return $this->getIsNewRecord() ? $this->insert($attributes) : $this->update($attributes); - } - else - { + } else { return false; } } @@ -798,8 +774,7 @@ abstract class ActiveRecord extends \yii\base\Model $event = new CModelEvent($this); $this->onBeforeSave($event); return $event->isValid; - } else - { + } else { return true; } } @@ -830,8 +805,7 @@ abstract class ActiveRecord extends \yii\base\Model $event = new CModelEvent($this); $this->onBeforeDelete($event); return $event->isValid; - } else - { + } else { return true; } } @@ -910,11 +884,8 @@ abstract class ActiveRecord extends \yii\base\Model if ($table->sequenceName !== null) { if (is_string($primaryKey) && $this->$primaryKey === null) { $this->$primaryKey = $builder->getLastInsertID($table); - } - elseif (is_array($primaryKey)) - { - foreach ($primaryKey as $pk) - { + } elseif (is_array($primaryKey)) { + foreach ($primaryKey as $pk) { if ($this->$pk === null) { $this->$pk = $builder->getLastInsertID($table); break; @@ -955,8 +926,7 @@ abstract class ActiveRecord extends \yii\base\Model $this->_pk = $this->getPrimaryKey(); $this->afterSave(); return true; - } else - { + } else { return false; } } @@ -984,13 +954,10 @@ abstract class ActiveRecord extends \yii\base\Model if (!$this->getIsNewRecord()) { Yii::trace(get_class($this) . '.saveAttributes()', 'system.db.ar.ActiveRecord'); $values = array(); - foreach ($attributes as $name => $value) - { + foreach ($attributes as $name => $value) { if (is_integer($name)) { $values[$value] = $this->$value; - } - else - { + } else { $values[$name] = $this->$name = $value; } } @@ -1000,12 +967,10 @@ abstract class ActiveRecord extends \yii\base\Model if ($this->updateByPk($this->getOldPrimaryKey(), $values) > 0) { $this->_pk = $this->getPrimaryKey(); return true; - } else - { + } else { return false; } - } else - { + } else { throw new Exception(Yii::t('yii', 'The active record cannot be updated because it is new.')); } } @@ -1032,13 +997,11 @@ abstract class ActiveRecord extends \yii\base\Model $criteria = $builder->createPkCriteria($table, $this->getOldPrimaryKey()); $command = $builder->createUpdateCounterCommand($this->getTableSchema(), $counters, $criteria); if ($command->execute()) { - foreach ($counters as $name => $value) - { + foreach ($counters as $name => $value) { $this->$name = $this->$name + $value; } return true; - } else - { + } else { return false; } } @@ -1056,12 +1019,10 @@ abstract class ActiveRecord extends \yii\base\Model $result = $this->deleteByPk($this->getPrimaryKey()) > 0; $this->afterDelete(); return $result; - } else - { + } else { return false; } - } else - { + } else { throw new Exception(Yii::t('yii', 'The active record cannot be deleted because it is new.')); } } @@ -1076,19 +1037,15 @@ abstract class ActiveRecord extends \yii\base\Model if (!$this->getIsNewRecord() && ($record = $this->findByPk($this->getPrimaryKey())) !== null) { $this->_attributes = array(); $this->_related = array(); - foreach ($this->getMetaData()->columns as $name => $column) - { + foreach ($this->getMetaData()->columns as $name => $column) { if (property_exists($this, $name)) { $this->$name = $record->$name; - } - else - { + } else { $this->_attributes[$name] = $record->$name; } } return true; - } else - { + } else { return false; } } diff --git a/framework/db/ar/JoinElement.php b/framework/db/ar/JoinElement.php index f9a2bd6..2f4a71a 100644 --- a/framework/db/ar/JoinElement.php +++ b/framework/db/ar/JoinElement.php @@ -22,13 +22,21 @@ class JoinElement extends \yii\base\Object */ public $relation; /** - * @var JoinElement + * @var JoinElement the parent element that this element needs to join with */ public $parent; /** - * @var JoinElement[] + * @var JoinElement[] the child elements that need to join with this element */ public $children = array(); + /** + * @var JoinElement[] the child elements that have relations declared in the AR class of this element + */ + public $relatedChildren = array(); + /** + * @var boolean whether this element is only for join purpose. If true, data will also be populated into the AR of this element. + */ + public $joinOnly; public $columnAliases = array(); // alias => original name public $pkAlias = array(); // original name => alias @@ -36,12 +44,13 @@ class JoinElement extends \yii\base\Object public $records; public $relatedRecords; - public function __construct($parent, $relation) + public function __construct($relation, $parent, $relatedParent) { + $this->relation = $relation; if ($parent !== null) { $this->parent = $parent; - $this->relation = $relation; $parent->children[$relation->name] = $this; + $relatedParent->relatedChildren[$relation->name] = $this; } } @@ -68,18 +77,18 @@ class JoinElement extends \yii\base\Object } } $modelClass = $this->relation->modelClass; - $record = $modelClass::populateRecord($attributes); + $record = $modelClass::populateData($attributes); foreach ($this->children as $child) { if ($child->relation->select !== false) { - $record->initRelation($child->relation); + $record->initRelatedRecord($child->relation); } } $this->records[$pk] = $record; } // populate child records - foreach ($this->children as $child) { - if ($child->relation->select === false) { + foreach ($this->relatedChildren as $child) { + if ($child->relation->select === false || $child->joinOnly) { continue; } $childRecord = $child->populateData($row); @@ -102,10 +111,10 @@ class JoinElement extends \yii\base\Object public function buildQuery($query) { $tokens = array( - '@.' => $this->relation->tableAlias, - '?.' => $this->parent->relation->tableAlias, + '@.' => $this->relation->tableAlias . '.', + '?.' => $this->parent->relation->tableAlias . '.', ); - foreach ($this->buildSelect() as $column) { + foreach ($this->buildSelect($this->relation->select) as $column) { $query->select[] = strtr($column, $tokens); } @@ -117,32 +126,60 @@ class JoinElement extends \yii\base\Object $query->having[] = strtr($this->relation->having, $tokens); } - /* - * joinType; - on; - via; - orderby - groupby - join - params - */ + if ($this->relation->via !== null) { + $query->join[] = $this->relation->via; + } + + $modelClass = $this->relation->modelClass; + $tableName = $modelClass::tableName(); + $joinType = $this->relation->joinType === null ? 'LEFT JOIN' : $this->relation->joinType; + $join = "$joinType $tableName {$this->relation->tableAlias}"; + if ($this->relation->on !== null) { + $join .= ' ON ' . strtr($this->relation->on, $tokens); + } + $query->join[] = $join; + + + if ($this->relation->join !== null) { + $query->join[] = strtr($this->relation->join, $tokens); + } + + // todo: convert orderBy to array first + if ($this->relation->orderBy !== null) { + $query->orderBy[] = strtr($this->relation->orderBy, $tokens); + } + + // todo: convert groupBy to array first + if ($this->relation->groupBy !== null) { + $query->groupBy[] = strtr($this->relation->groupBy, $tokens); + } + + if ($this->relation->params !== null) { + foreach ($this->relation->params as $name => $value) { + if (is_integer($name)) { + $query->params[] = $value; + } else { + $query->params[$name] = $value; + } + } + } foreach ($this->children as $child) { $child->buildQuery($query); } } - public function buildSelect() + public function buildSelect($select) { $modelClass = $this->relation->modelClass; $tableSchema = $modelClass::getMetaData()->table; - $select = $this->relation->select; $columns = array(); $columnCount = 0; + $prefix = $this->relation->tableAlias; if (empty($select) || $select === '*') { foreach ($tableSchema->columns as $column) { - $alias = $this->tableAlias . '_' . ($columnCount++); - $columns[] = "{$column->name} AS $alias"; + $alias = $this->relation->tableAlias . '_' . ($columnCount++); + $columns[] = "$prefix.{$column->name} AS $alias"; $this->columnAliases[$alias] = $column->name; if ($column->isPrimaryKey) { $this->pkAlias[$column->name] = $alias; @@ -153,8 +190,8 @@ class JoinElement extends \yii\base\Object $select = explode(',', $select); } foreach ($tableSchema->primaryKey as $column) { - $alias = $this->tableAlias . '_' . ($columnCount++); - $columns[] = "$column AS $alias"; + $alias = $this->relation->tableAlias . '_' . ($columnCount++); + $columns[] = "$prefix.$column AS $alias"; $this->pkAlias[$column] = $alias; } foreach ($select as $column) { @@ -164,8 +201,8 @@ class JoinElement extends \yii\base\Object $this->columnAliases[$matches[2]] = $matches[2]; $columns[] = $column; } elseif (!isset($this->pkAlias[$column])) { - $alias = $this->tableAlias . '_' . ($columnCount++); - $columns[] = "$column AS $alias"; + $alias = $this->relation->tableAlias . '_' . ($columnCount++); + $columns[] = "$prefix.$column AS $alias"; $this->columnAliases[$alias] = $column; } } diff --git a/framework/db/dao/QueryBuilder.php b/framework/db/dao/QueryBuilder.php index 0fa41c5..4e03c62 100644 --- a/framework/db/dao/QueryBuilder.php +++ b/framework/db/dao/QueryBuilder.php @@ -656,7 +656,7 @@ class QueryBuilder extends \yii\base\Object if (is_object($column)) { $columns[$i] = (string)$column; } elseif (strpos($column, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)([\w\-\.])$/', $column, $matches)) { + if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)([\w\-_\.]+)$/', $column, $matches)) { $columns[$i] = $driver->quoteColumnName($matches[1]) . ' AS ' . $driver->quoteSimpleColumnName($matches[2]); } else { $columns[$i] = $driver->quoteColumnName($column); diff --git a/tests/unit/data/ar/Customer.php b/tests/unit/data/ar/Customer.php index ed40c4d..02af604 100644 --- a/tests/unit/data/ar/Customer.php +++ b/tests/unit/data/ar/Customer.php @@ -8,4 +8,13 @@ class Customer extends ActiveRecord { return 'tbl_customer'; } + + public static function relations() + { + return array( + 'orders:Order[]' => array( + 'on' => '@.customer_id = ?.id', + ), + ); + } } \ No newline at end of file diff --git a/tests/unit/data/ar/Order.php b/tests/unit/data/ar/Order.php index b37202d..5e0d4b6 100644 --- a/tests/unit/data/ar/Order.php +++ b/tests/unit/data/ar/Order.php @@ -8,4 +8,13 @@ class Order extends ActiveRecord { return 'tbl_order'; } + + public static function relations() + { + return array( + 'customer:Customer' => array( + 'on' => '@.id = ?.customer_id', + ), + ); + } } \ No newline at end of file diff --git a/tests/unit/data/mysql.sql b/tests/unit/data/mysql.sql index 1b5f9d6..65a6422 100644 --- a/tests/unit/data/mysql.sql +++ b/tests/unit/data/mysql.sql @@ -86,7 +86,7 @@ INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2); INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0); INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (3, 1325502201, 40.0); +INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); diff --git a/tests/unit/framework/db/ar/ActiveRecordTest.php b/tests/unit/framework/db/ar/ActiveRecordTest.php index adc536b..f344c4f 100644 --- a/tests/unit/framework/db/ar/ActiveRecordTest.php +++ b/tests/unit/framework/db/ar/ActiveRecordTest.php @@ -116,6 +116,18 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase $this->assertEquals(3, $customer->id); $this->assertEquals(null, $customer->name); } + + public function testEagerLoading() + { + $customers = Customer::find()->with('orders')->orderBy('t0.id')->all(); + $this->assertEquals(3, count($customers)); + $this->assertEquals(1, count($customers[0]->orders)); + $this->assertEquals(2, count($customers[1]->orders)); + $this->assertEquals(0, count($customers[2]->orders)); + + $customers = Customer::find()->with('orders.customer')->orderBy('t0.id')->all(); + } + /* public function testGetSql() {