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 ...
* todo: lazy loading
* todo: clean up joinOnly and select=false
* todo: records for index != null, asArray = true
* todo: refactor code
* todo: count with
* todo: findBySql and lazy loading cannot apply scopes for primary table
@ -84,14 +83,15 @@ class ActiveFinder extends \yii\base\Object
}
$this->applyScopes($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) {
$alias = $this->connection->quoteTableName($query->tableAlias) . '.';
} else {
$class = $query->modelClass;
$alias = $this->connection->quoteTableName($class::tableName()) . '.';
}
$sql = str_replace('@.', $alias, $sql);
$sql = str_replace($prefix, $alias, $sql);
}
}
$command = $this->connection->createCommand($sql, $query->params);
@ -125,18 +125,31 @@ class ActiveFinder extends \yii\base\Object
return $records;
}
/**
* @param ActiveRecord $record
* @param ActiveRelation $relation
* @return array
*/
public function findRelatedRecords($record, $relation)
{
$this->_joinCount = 0;
$this->_tableAliases = array();
$this->_hasMany = false;
$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);
$child = $this->buildJoinTree($joinTree, $relation->name);
$child->query = $relation;
$child->container = null;
$this->buildJoinTree($child, $relation->with);
$this->initJoinTree($joinTree);
// todo: set where by pk
$pk = $record->getPrimaryKey(true);
$this->addPkCondition($query, $table, array($pk), $query->tableAlias . '.');
$q = new Query;
$this->buildJoinQuery($joinTree, $q);
@ -146,16 +159,13 @@ class ActiveFinder extends \yii\base\Object
}
$rows = $q->createCommand($this->connection)->queryAll();
$joinTree->populateData($rows);
$child->populateData($rows);
if ($query->index !== null) {
$records = array();
foreach ($joinTree->records as $record) {
$records[$record[$query->index]] = $record;
}
$records = $relation->index === null ? array_values($child->records) : $child->records;
if ($relation->hasMany) {
return $records;
} 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)
{
if (count($table->primaryKey) === 1) {
if (count($table->primaryKey) === 1 && count($rows) > 1) {
$name = $table->primaryKey[0];
$values = array();
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])) {
return null;
} 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];
} else {
return $this->_related[$name] = $this->findByRelation($md->relations[$name]);
@ -555,6 +555,7 @@ abstract class ActiveRecord extends Model
}
$relation = $md->relations[$relation];
}
$relation = clone $relation;
foreach ($params as $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)
*/
public $records;
public $related;
public $records = array();
public $related = array();
/**
* @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']));
}
/*
public function testGetSql()
{
// sql for all
$sql = Customer::find()->sql;
$this->assertEquals('SELECT * FROM `tbl_customer`', $sql);
// sql for one row
$sql = Customer::find()->oneSql;
$this->assertEquals('SELECT * FROM tbl_customer LIMIT 1', $sql);
// sql for count
$sql = Customer::find()->countSql;
$this->assertEquals('SELECT COUNT(*) FROM tbl_customer', $sql);
}
public function testArrayResult()
{
Customer::find()->asArray()->one();
Customer::find()->asArray()->all();
}
public function testMisc()
{
// Customer::exists()
// Customer::updateAll()
// Customer::updateCounters()
// Customer::deleteAll()
}
public function testLazyLoading()
{
}
public function testEagerLoading()
{
}
*/
public function testLazyLoading()
{
// has one
$order = Order::find(3)->one();
$this->assertTrue($order->customer instanceof Customer);
$this->assertEquals(2, $order->customer->id);
// has many
$customer = Customer::find(2)->one();
$orders = $customer->orders;
$this->assertEquals(2, count($orders));
$this->assertEquals(2, $orders[0]->id);
$this->assertEquals(3, $orders[1]->id);
// has many via join table
$orders = Order::find()->order('@.id')->all();
$this->assertEquals(3, count($orders));
$this->assertEquals(2, count($orders[0]->books));
$this->assertEquals(1, $orders[0]->books[0]->id);
$this->assertEquals(2, $orders[0]->books[1]->id);
$this->assertEquals(array(), $orders[1]->books);
$this->assertEquals(1, count($orders[2]->books));
$this->assertEquals(2, $orders[2]->books[0]->id);
// customized relation query
$customer = Customer::find(2)->one();
$orders = $customer->orders(array(
'where' => '@.id = 3',
));
$this->assertEquals(1, count($orders));
$this->assertEquals(3, $orders[0]->id);
// 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);
// 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