Browse Source

finished AR findBySql and eager loading.

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
0e40fb4a61
  1. 61
      framework/db/ar/ActiveFinder.php
  2. 2
      framework/db/ar/JoinElement.php
  3. 3
      tests/unit/framework/db/ar/ActiveRecordTest.php

61
framework/db/ar/ActiveFinder.php

@ -17,9 +17,10 @@ use yii\db\Exception;
/** /**
* ActiveFinder.php is ... * ActiveFinder.php is ...
* todo: base limited with has_many, bySQL, lazy loading * todo: lazy loading
* todo: quoting column names in 'on' clause * todo: clean up joinOnly and select=false
* * todo: records for index != null, asArray = true
* todo: refactor code
* @property integer $count * @property integer $count
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
@ -72,6 +73,11 @@ class ActiveFinder extends \yii\base\Object
$command = $this->connection->createCommand($sql, $query->params); $command = $this->connection->createCommand($sql, $query->params);
$rows = $command->queryAll(); $rows = $command->queryAll();
return $this->createRecords($query, $rows);
}
protected function createRecords($query, $rows)
{
$records = array(); $records = array();
if ($query->asArray) { if ($query->asArray) {
if ($query->index === null) { if ($query->index === null) {
@ -111,10 +117,38 @@ class ActiveFinder extends \yii\base\Object
*/ */
public function findRecordsWithRelations($query) public function findRecordsWithRelations($query)
{ {
if ($query->sql !== null) {
$command = $this->connection->createCommand($query->sql, $query->params);
$rows = $command->queryAll();
$records = $this->createRecords($query, $rows);
$q = new ActiveQuery($query->modelClass);
$q->with = $query->with;
$q->tableAlias = 't';
$q->asArray = $query->asArray;
$q->index = $query->index;
$modelClass = $query->modelClass;
$table = $modelClass::getMetaData()->table;
$q->select = $table->primaryKey;
$this->addPkCondition($q, $table, $rows, 't.');
$query = $q;
}
$this->_joinCount = 0; $this->_joinCount = 0;
$this->_tableAliases = array(); $this->_tableAliases = array();
$this->_hasMany = false; $this->_hasMany = false;
$joinTree = new JoinElement($this->_joinCount++, $query, null, null); $joinTree = new JoinElement($this->_joinCount++, $query, null, null);
if (isset($records)) {
foreach ($records as $record) {
$pk = array();
foreach ($table->primaryKey as $name) {
$pk[] = $record[$name];
}
$pk = count($pk) === 1 ? $pk[0] : serialize($pk);
$joinTree->records[$pk] = $record;
}
}
$this->buildJoinTree($joinTree, $query->with); $this->buildJoinTree($joinTree, $query->with);
$this->initJoinTree($joinTree); $this->initJoinTree($joinTree);
@ -143,6 +177,9 @@ class ActiveFinder extends \yii\base\Object
protected function applyScopes($query) protected function applyScopes($query)
{ {
if ($query->modelClass === null || $query instanceof ActiveQuery && $query->sql !== null) {
return;
}
$class = $query->modelClass; $class = $query->modelClass;
$class::defaultScope($query); $class::defaultScope($query);
if (is_array($query->scopes)) { if (is_array($query->scopes)) {
@ -262,9 +299,7 @@ class ActiveFinder extends \yii\base\Object
$this->_tableAliases[$alias] = true; $this->_tableAliases[$alias] = true;
$element->query->tableAlias = $alias; $element->query->tableAlias = $alias;
if ($element->query->modelClass !== null) {
$this->applyScopes($element->query); $this->applyScopes($element->query);
}
foreach ($element->children as $child) { foreach ($element->children as $child) {
$this->initJoinTree($child, $count); $this->initJoinTree($child, $count);
@ -455,29 +490,35 @@ class ActiveFinder extends \yii\base\Object
} }
$q->distinct = true; $q->distinct = true;
$rows = $q->createCommand($this->connection)->queryAll(); $rows = $q->createCommand($this->connection)->queryAll();
$prefix = $activeQuery->tableAlias . '.';
$this->addPkCondition($query, $table, $rows, $prefix);
$query->limit = $query->offset = null;
}
protected function addPkCondition($query, $table, $rows, $prefix)
{
if (count($table->primaryKey) === 1) { if (count($table->primaryKey) === 1) {
$name = $table->primaryKey[0]; $name = $table->primaryKey[0];
$values = array(); $values = array();
foreach ($rows as $row) { foreach ($rows as $row) {
$values[] = $table->columns[$name]->typecast($row[$name]); $values[] = $table->columns[$name]->typecast($row[$name]);
} }
$query->andWhere(array('in', $activeQuery->tableAlias . '.' . $name, $values)); $query->andWhere(array('in', $prefix . $name, $values));
} else { } else {
$ors = array('or'); $ors = array('or');
$prefix = $this->connection->quoteTableName($activeQuery->tableAlias, true) . '.'; $prefix = $this->connection->quoteTableName($activeQuery->tableAlias, true) . '.';
foreach ($rows as $row) { foreach ($rows as $row) {
$ands = array(); $hash = array();
foreach ($table->primaryKey as $name) { foreach ($table->primaryKey as $name) {
$value = $table->columns[$name]->typecast($row[$name]); $value = $table->columns[$name]->typecast($row[$name]);
if (is_string($value)) { if (is_string($value)) {
$value = $this->connection->quoteValue($value); $value = $this->connection->quoteValue($value);
} }
$ands[] = $prefix . $this->connection->quoteColumnName($name, true) . '=' . $value; $hash[$prefix . $name] = $value;
} }
$ors[] = implode(' AND ', $ands); $ors[] = $hash;
} }
$query->andWhere($ors); $query->andWhere($ors);
} }
$query->limit = $query->offset = null;
} }
} }

2
framework/db/ar/JoinElement.php

@ -95,7 +95,7 @@ class JoinElement extends \yii\base\Object
$modelClass = $this->query->modelClass; $modelClass = $this->query->modelClass;
$this->records[$pk] = $record = $modelClass::create($attributes); $this->records[$pk] = $record = $modelClass::create($attributes);
foreach ($this->children as $child) { foreach ($this->children as $child) {
if ($child->query->select !== false || $child->joinOnly) { if ($child->query->select !== false && !$child->joinOnly) {
$record->initRelation($child->query); $record->initRelation($child->query);
} }
} }

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

@ -253,6 +253,9 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$orders = Order::find()->with('items')->order('@.id')->limit(2)->all(); $orders = Order::find()->with('items')->order('@.id')->limit(2)->all();
$this->assertEquals(2, count($orders)); $this->assertEquals(2, count($orders));
$orders = Order::findBySql('SELECT * FROM tbl_order WHERE customer_id=2')->with('items')->all();
$this->assertEquals(2, count($orders));
} }
/* /*

Loading…
Cancel
Save