Browse Source

...

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
df003215de
  1. 57
      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

57
framework/db/ar/ActiveFinder.php

@ -192,14 +192,32 @@ class ActiveFinder extends \yii\base\Object
throw new Exception("$modelClass has no relation named '$with'.");
}
$relation = clone $relations[$with];
if (is_string($relation->via) && isset($relations[$relation->via])) {
if (is_string($relation->via)) {
// join via an existing relation
$parent2 = $this->buildJoinTree($parent, $relation->via);
$relation->via = null;
if ($parent2->joinOnly === null) {
$parent2->joinOnly = true;
}
$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 {
$child = new JoinElement($this->_joinCount++, $relation, $parent, $parent);
}
@ -239,7 +257,9 @@ class ActiveFinder extends \yii\base\Object
$this->_tableAliases[$alias] = true;
$element->query->tableAlias = $alias;
if ($element->query->modelClass !== null) {
$this->applyScopes($element->query);
}
foreach ($element->children as $child) {
$this->initJoinTree($child, $count);
@ -298,22 +318,41 @@ class ActiveFinder extends \yii\base\Object
}
if ($element->query instanceof ActiveRelation) {
if (is_array($element->query->via)) {
// todo: join via a pivot table
// $query->join[] = strtr($element->query->via, $quotedPrefixes);
}
$joinType =
if ($element->query->joinType === null) {
$joinType = $element->query->select === false ? 'INNER JOIN' : 'LEFT JOIN';
$joinType = 'LEFT JOIN';
} else {
$joinType = $element->query->joinType;
}
if ($element->query->modelClass !== null) {
$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);
$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) {
$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;
}

14
framework/db/ar/ActiveRelation.php

@ -23,12 +23,9 @@ class ActiveRelation extends BaseActiveQuery
*/
public $name;
/**
* @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.
* @var string the name of the table
*/
public $link;
public $table;
/**
* @var boolean whether this relation is a one-many relation
*/
@ -39,6 +36,13 @@ class ActiveRelation extends BaseActiveQuery
*/
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
*/
public $on;

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

@ -16,7 +16,7 @@ class Customer extends ActiveRecord
{
return array(
'orders:Order[]' => array(
'on' => '@.customer_id = ?.id',
'link' => array('customer_id' => 'id'),
),
);
}
@ -25,7 +25,7 @@ class Customer extends ActiveRecord
{
return array(
'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(
'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(
'order:Order' => array(
'on' => '@.order_id = ?.id',
'link' => array('order_id' => 'id'),
),
'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\Customer;
use yiiunit\data\ar\OrderItem;
use yiiunit\data\ar\Order;
class ActiveRecordTest extends \yiiunit\MysqlTestCase
{
@ -185,7 +186,7 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase
// count
$query = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC');
$query->one();
$this->assertEquals(1, $query->count);
$this->assertEquals(3, $query->count);
$query = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC');
$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(2, $customers[1]->orders[0]->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