Browse Source

...

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
df003215de
  1. 63
      framework/db/ar/ActiveFinder.php
  2. 14
      framework/db/ar/ActiveRelation.php
  3. 4
      tests/unit/data/ar/Customer.php
  4. 25
      tests/unit/data/ar/Order.php
  5. 4
      tests/unit/data/ar/OrderItem.php
  6. 17
      tests/unit/framework/db/ar/ActiveRecordTest.php

63
framework/db/ar/ActiveFinder.php

@ -192,14 +192,32 @@ class ActiveFinder extends \yii\base\Object
throw new Exception("$modelClass has no relation named '$with'."); throw new Exception("$modelClass has no relation named '$with'.");
} }
$relation = clone $relations[$with]; $relation = clone $relations[$with];
if (is_string($relation->via) && isset($relations[$relation->via])) { if (is_string($relation->via)) {
// join via an existing relation // join via an existing relation
$parent2 = $this->buildJoinTree($parent, $relation->via); $parent2 = $this->buildJoinTree($parent, $relation->via);
$relation->via = null;
if ($parent2->joinOnly === null) { if ($parent2->joinOnly === null) {
$parent2->joinOnly = true; $parent2->joinOnly = true;
} }
$child = new JoinElement($this->_joinCount++, $relation, $parent2, $parent); $child = new JoinElement($this->_joinCount++, $relation, $parent2, $parent);
} elseif (is_array($relation->via)) {
// join via a pivoting table
$r = new ActiveRelation;
$r->name = 'pt' . $this->_joinCount;
$r->hasMany = $relation->hasMany;
foreach ($relation->via as $name => $value) {
$r->$name = $value;
}
$r->select = false;
if ($r->joinType === null) {
$r->joinType = $relation->joinType;
}
$parent2 = new JoinElement($this->_joinCount++, $r, $parent, $parent);
$parent2->joinOnly = true;
$child = new JoinElement($this->_joinCount++, $relation, $parent2, $parent);
} else { } else {
$child = new JoinElement($this->_joinCount++, $relation, $parent, $parent); $child = new JoinElement($this->_joinCount++, $relation, $parent, $parent);
} }
@ -239,7 +257,9 @@ class ActiveFinder extends \yii\base\Object
$this->_tableAliases[$alias] = true; $this->_tableAliases[$alias] = true;
$element->query->tableAlias = $alias; $element->query->tableAlias = $alias;
$this->applyScopes($element->query); if ($element->query->modelClass !== null) {
$this->applyScopes($element->query);
}
foreach ($element->children as $child) { foreach ($element->children as $child) {
$this->initJoinTree($child, $count); $this->initJoinTree($child, $count);
@ -298,22 +318,41 @@ class ActiveFinder extends \yii\base\Object
} }
if ($element->query instanceof ActiveRelation) { if ($element->query instanceof ActiveRelation) {
if (is_array($element->query->via)) { $joinType =
// todo: join via a pivot table
// $query->join[] = strtr($element->query->via, $quotedPrefixes);
}
if ($element->query->joinType === null) { if ($element->query->joinType === null) {
$joinType = $element->query->select === false ? 'INNER JOIN' : 'LEFT JOIN'; $joinType = 'LEFT JOIN';
} else { } else {
$joinType = $element->query->joinType; $joinType = $element->query->joinType;
} }
$modelClass = $element->query->modelClass; if ($element->query->modelClass !== null) {
$tableName = $this->connection->quoteTableName($modelClass::tableName()); $modelClass = $element->query->modelClass;
$tableName = $this->connection->quoteTableName($modelClass::tableName());
} else {
$tableName = $this->connection->quoteTableName($element->query->table);
}
$tableAlias = $this->connection->quoteTableName($element->query->tableAlias); $tableAlias = $this->connection->quoteTableName($element->query->tableAlias);
$join = "$joinType $tableName $tableAlias"; $join = "$joinType $tableName $tableAlias";
$on = '';
if (is_array($element->query->link)) {
foreach ($element->query->link as $pk => $fk) {
$pk = $quotedPrefixes['@.'] . $this->connection->quoteColumnName($pk, true);
$fk = $quotedPrefixes['?.'] . $this->connection->quoteColumnName($fk, true);
if ($on !== '') {
$on .= ' AND ';
}
$on .= "$pk = $fk";
}
}
if ($element->query->on !== null) { if ($element->query->on !== null) {
$join .= ' ON ' . strtr($qb->buildCondition($element->query->on), $quotedPrefixes); $condition = strtr($qb->buildCondition($element->query->on), $quotedPrefixes);
if ($on !== '') {
$on .= " AND ($condition)";
} else {
$on = $condition;
}
}
if ($on !== '') {
$join .= ' ON ' . $on;
} }
$query->join[] = $join; $query->join[] = $join;
} }

14
framework/db/ar/ActiveRelation.php

@ -23,12 +23,9 @@ class ActiveRelation extends BaseActiveQuery
*/ */
public $name; public $name;
/** /**
* @var array the columns of the primary and foreign tables that establish the relation. * @var string the name of the table
* The array keys must be columns of the table for this relation, and the array values
* must be the corresponding columns from the primary table. Do not prefix or quote the column names.
* They will be done automatically by Yii.
*/ */
public $link; public $table;
/** /**
* @var boolean whether this relation is a one-many relation * @var boolean whether this relation is a one-many relation
*/ */
@ -39,6 +36,13 @@ class ActiveRelation extends BaseActiveQuery
*/ */
public $joinType; public $joinType;
/** /**
* @var array the columns of the primary and foreign tables that establish the relation.
* The array keys must be columns of the table for this relation, and the array values
* must be the corresponding columns from the primary table. Do not prefix or quote the column names.
* They will be done automatically by Yii.
*/
public $link;
/**
* @var string the ON clause of the join query * @var string the ON clause of the join query
*/ */
public $on; public $on;

4
tests/unit/data/ar/Customer.php

@ -16,7 +16,7 @@ class Customer extends ActiveRecord
{ {
return array( return array(
'orders:Order[]' => array( 'orders:Order[]' => array(
'on' => '@.customer_id = ?.id', 'link' => array('customer_id' => 'id'),
), ),
); );
} }
@ -25,7 +25,7 @@ class Customer extends ActiveRecord
{ {
return array( return array(
'active' => function($q) { 'active' => function($q) {
return $q->andWhere('@.status = ' . self::STATUS_ACTIVE); return $q->andWhere('@.`status` = ' . Customer::STATUS_ACTIVE);
}, },
); );
} }

25
tests/unit/data/ar/Order.php

@ -13,7 +13,30 @@ class Order extends ActiveRecord
{ {
return array( return array(
'customer:Customer' => array( 'customer:Customer' => array(
'on' => '@.id = ?.customer_id', 'link' => array('id' => 'customer_id'),
),
'orderItems:OrderItem' => array(
'link' => array('order_id' => 'id'),
),
'items:Item[]' => array(
'via' => 'orderItems',
'link' => array(
'id' => 'item_id',
),
'order' => '@.id',
),
'books:Item[]' => array(
'joinType' => 'INNER JOIN',
'via' => array(
'table' => 'tbl_order_item',
'link' => array(
'order_id' => 'id',
),
),
'link' => array(
'id' => 'item_id',
),
'on' => '@.category_id = 1',
), ),
); );
} }

4
tests/unit/data/ar/OrderItem.php

@ -13,10 +13,10 @@ class OrderItem extends ActiveRecord
{ {
return array( return array(
'order:Order' => array( 'order:Order' => array(
'on' => '@.order_id = ?.id', 'link' => array('order_id' => 'id'),
), ),
'item:Item' => array( 'item:Item' => array(
'on' => '@.item_id = ?.id', 'link' => array('item_id' => 'id'),
), ),
); );
} }

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

@ -7,6 +7,7 @@ use yii\db\ar\ActiveQuery;
use yiiunit\data\ar\ActiveRecord; use yiiunit\data\ar\ActiveRecord;
use yiiunit\data\ar\Customer; use yiiunit\data\ar\Customer;
use yiiunit\data\ar\OrderItem; use yiiunit\data\ar\OrderItem;
use yiiunit\data\ar\Order;
class ActiveRecordTest extends \yiiunit\MysqlTestCase class ActiveRecordTest extends \yiiunit\MysqlTestCase
{ {
@ -185,7 +186,7 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
// count // count
$query = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC'); $query = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC');
$query->one(); $query->one();
$this->assertEquals(1, $query->count); $this->assertEquals(3, $query->count);
$query = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC'); $query = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC');
$this->assertEquals(3, $query->count); $this->assertEquals(3, $query->count);
} }
@ -235,6 +236,20 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
$this->assertEquals(1, $customers[0]->orders[0]->customer->id); $this->assertEquals(1, $customers[0]->orders[0]->customer->id);
$this->assertEquals(2, $customers[1]->orders[0]->customer->id); $this->assertEquals(2, $customers[1]->orders[0]->customer->id);
$this->assertEquals(2, $customers[1]->orders[1]->customer->id); $this->assertEquals(2, $customers[1]->orders[1]->customer->id);
$orders = Order::find()->with('items')->order('@.id')->all();
$this->assertEquals(3, count($orders));
$this->assertEquals(1, $orders[0]->items[0]->id);
$this->assertEquals(2, $orders[0]->items[1]->id);
$this->assertEquals(3, $orders[1]->items[0]->id);
$this->assertEquals(4, $orders[1]->items[1]->id);
$this->assertEquals(5, $orders[1]->items[2]->id);
$orders = Order::find()->with('books')->order('@.id')->all();
$this->assertEquals(2, count($orders));
$this->assertEquals(1, $orders[0]->books[0]->id);
$this->assertEquals(2, $orders[0]->books[1]->id);
$this->assertEquals(2, $orders[1]->books[0]->id);
} }
/* /*

Loading…
Cancel
Save