Browse Source

Finished AR query.

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
5ddc1ba18a
  1. 34
      framework/db/ar/ActiveFinder.php
  2. 3
      framework/db/ar/ActiveRecord.php
  3. 4
      framework/db/ar/JoinElement.php
  4. 86
      tests/unit/framework/db/ar/ActiveRecordTest.php

34
framework/db/ar/ActiveFinder.php

@ -19,7 +19,6 @@ use yii\db\Exception;
* ActiveFinder.php is ... * ActiveFinder.php is ...
* todo: lazy loading * todo: lazy loading
* todo: clean up joinOnly and select=false * todo: clean up joinOnly and select=false
* todo: records for index != null, asArray = true
* todo: refactor code * todo: refactor code
* todo: count with * todo: count with
* todo: findBySql and lazy loading cannot apply scopes for primary table * todo: findBySql and lazy loading cannot apply scopes for primary table
@ -84,14 +83,15 @@ class ActiveFinder extends \yii\base\Object
} }
$this->applyScopes($query); $this->applyScopes($query);
$sql = $this->connection->getQueryBuilder()->build($query); $sql = $this->connection->getQueryBuilder()->build($query);
if (strpos($sql, '@.') !== false) { $prefix = $this->connection->quoteTableName('@', true) . '.';
if (strpos($sql, $prefix) !== false) {
if ($query->tableAlias !== null) { if ($query->tableAlias !== null) {
$alias = $this->connection->quoteTableName($query->tableAlias) . '.'; $alias = $this->connection->quoteTableName($query->tableAlias) . '.';
} else { } else {
$class = $query->modelClass; $class = $query->modelClass;
$alias = $this->connection->quoteTableName($class::tableName()) . '.'; $alias = $this->connection->quoteTableName($class::tableName()) . '.';
} }
$sql = str_replace('@.', $alias, $sql); $sql = str_replace($prefix, $alias, $sql);
} }
} }
$command = $this->connection->createCommand($sql, $query->params); $command = $this->connection->createCommand($sql, $query->params);
@ -125,18 +125,31 @@ class ActiveFinder extends \yii\base\Object
return $records; return $records;
} }
/**
* @param ActiveRecord $record
* @param ActiveRelation $relation
* @return array
*/
public function findRelatedRecords($record, $relation) public function findRelatedRecords($record, $relation)
{ {
$this->_joinCount = 0; $this->_joinCount = 0;
$this->_tableAliases = array(); $this->_tableAliases = array();
$this->_hasMany = false; $this->_hasMany = false;
$query = new ActiveQuery(get_class($record)); $query = new ActiveQuery(get_class($record));
$modelClass = $query->modelClass;
$table = $modelClass::getMetaData()->table;
$query->select = $table->primaryKey;
$query->limit = $relation->limit;
$query->offset = $relation->offset;
$joinTree = new JoinElement($this->_joinCount++, $query, null, null); $joinTree = new JoinElement($this->_joinCount++, $query, null, null);
$child = $this->buildJoinTree($joinTree, $relation->name); $child = $this->buildJoinTree($joinTree, $relation->name);
$child->query = $relation;
$child->container = null;
$this->buildJoinTree($child, $relation->with); $this->buildJoinTree($child, $relation->with);
$this->initJoinTree($joinTree); $this->initJoinTree($joinTree);
// todo: set where by pk $pk = $record->getPrimaryKey(true);
$this->addPkCondition($query, $table, array($pk), $query->tableAlias . '.');
$q = new Query; $q = new Query;
$this->buildJoinQuery($joinTree, $q); $this->buildJoinQuery($joinTree, $q);
@ -146,16 +159,13 @@ class ActiveFinder extends \yii\base\Object
} }
$rows = $q->createCommand($this->connection)->queryAll(); $rows = $q->createCommand($this->connection)->queryAll();
$joinTree->populateData($rows); $child->populateData($rows);
if ($query->index !== null) { $records = $relation->index === null ? array_values($child->records) : $child->records;
$records = array(); if ($relation->hasMany) {
foreach ($joinTree->records as $record) {
$records[$record[$query->index]] = $record;
}
return $records; return $records;
} else { } else {
return array_values($joinTree->records); return $records === array() ? null : reset($records);
} }
} }
@ -563,7 +573,7 @@ class ActiveFinder extends \yii\base\Object
protected function addPkCondition($query, $table, $rows, $prefix) protected function addPkCondition($query, $table, $rows, $prefix)
{ {
if (count($table->primaryKey) === 1) { if (count($table->primaryKey) === 1 && count($rows) > 1) {
$name = $table->primaryKey[0]; $name = $table->primaryKey[0];
$values = array(); $values = array();
foreach ($rows as $row) { foreach ($rows as $row) {

3
framework/db/ar/ActiveRecord.php

@ -425,7 +425,7 @@ abstract class ActiveRecord extends Model
if (isset($md->table->columns[$name])) { if (isset($md->table->columns[$name])) {
return null; return null;
} elseif (isset($md->relations[$name])) { } elseif (isset($md->relations[$name])) {
if (array_key_exists($name, $this->_related)) { if (isset($this->_related[$name]) || $this->_related !== null && array_key_exists($name, $this->_related)) {
return $this->_related[$name]; return $this->_related[$name];
} else { } else {
return $this->_related[$name] = $this->findByRelation($md->relations[$name]); return $this->_related[$name] = $this->findByRelation($md->relations[$name]);
@ -555,6 +555,7 @@ abstract class ActiveRecord extends Model
} }
$relation = $md->relations[$relation]; $relation = $md->relations[$relation];
} }
$relation = clone $relation;
foreach ($params as $name => $value) { foreach ($params as $name => $value) {
$relation->$name = $value; $relation->$name = $value;
} }

4
framework/db/ar/JoinElement.php

@ -57,8 +57,8 @@ class JoinElement extends \yii\base\Object
/** /**
* @var array query results for this element (PK value => AR instance or data array) * @var array query results for this element (PK value => AR instance or data array)
*/ */
public $records; public $records = array();
public $related; public $related = array();
/** /**
* @param integer $id * @param integer $id

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

@ -267,45 +267,49 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$this->assertTrue(is_array($customers[1]['orders'][0]['customer'])); $this->assertTrue(is_array($customers[1]['orders'][0]['customer']));
} }
/* public function testLazyLoading()
public function testGetSql() {
{ // has one
// sql for all $order = Order::find(3)->one();
$sql = Customer::find()->sql; $this->assertTrue($order->customer instanceof Customer);
$this->assertEquals('SELECT * FROM `tbl_customer`', $sql); $this->assertEquals(2, $order->customer->id);
// sql for one row // has many
$sql = Customer::find()->oneSql; $customer = Customer::find(2)->one();
$this->assertEquals('SELECT * FROM tbl_customer LIMIT 1', $sql); $orders = $customer->orders;
$this->assertEquals(2, count($orders));
// sql for count $this->assertEquals(2, $orders[0]->id);
$sql = Customer::find()->countSql; $this->assertEquals(3, $orders[1]->id);
$this->assertEquals('SELECT COUNT(*) FROM tbl_customer', $sql);
} // has many via join table
$orders = Order::find()->order('@.id')->all();
public function testArrayResult() $this->assertEquals(3, count($orders));
{ $this->assertEquals(2, count($orders[0]->books));
Customer::find()->asArray()->one(); $this->assertEquals(1, $orders[0]->books[0]->id);
Customer::find()->asArray()->all(); $this->assertEquals(2, $orders[0]->books[1]->id);
} $this->assertEquals(array(), $orders[1]->books);
$this->assertEquals(1, count($orders[2]->books));
public function testMisc() $this->assertEquals(2, $orders[2]->books[0]->id);
{
// Customer::exists() // customized relation query
// Customer::updateAll() $customer = Customer::find(2)->one();
// Customer::updateCounters() $orders = $customer->orders(array(
// Customer::deleteAll() 'where' => '@.id = 3',
} ));
$this->assertEquals(1, count($orders));
$this->assertEquals(3, $orders[0]->id);
public function testLazyLoading() // original results are kept after customized query
{ $orders = $customer->orders;
$this->assertEquals(2, count($orders));
} $this->assertEquals(2, $orders[0]->id);
$this->assertEquals(3, $orders[1]->id);
public function testEagerLoading() // as array
{ $orders = $customer->orders(array(
'asArray' => true,
} ));
*/ $this->assertEquals(2, count($orders));
$this->assertTrue(is_array($orders[0]));
$this->assertEquals(2, $orders[0]['id']);
$this->assertEquals(3, $orders[1]['id']);
}
} }
Loading…
Cancel
Save