Browse Source

Delay joinWith till createCommand to correctly combine relation condition with primary condition.

tags/2.0.0-beta
Qiang Xue 11 years ago
parent
commit
a2edf01c85
  1. 40
      framework/db/ActiveQuery.php
  2. 20
      tests/unit/framework/db/ActiveRecordTest.php

40
framework/db/ActiveQuery.php

@ -86,6 +86,10 @@ class ActiveQuery extends Query implements ActiveQueryInterface
* @see onCondition()
*/
public $on;
/**
* @var array a list of relations that this query should be joined with
*/
public $joinWith;
/**
@ -232,6 +236,10 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/
protected function createCommandInternal($db)
{
if (!empty($this->joinWith)) {
$this->buildJoinWith();
}
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
if ($db === null) {
@ -330,24 +338,32 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/
public function joinWith($with, $eagerLoading = true, $joinType = 'LEFT JOIN')
{
$with = (array)$with;
$this->joinWithRelations(new $this->modelClass, $with, $joinType);
$this->joinWith[] = [(array)$with, $eagerLoading, $joinType];
return $this;
}
if (is_array($eagerLoading)) {
foreach ($with as $name => $callback) {
if (is_integer($name)) {
if (!in_array($callback, $eagerLoading, true)) {
private function buildJoinWith()
{
foreach ($this->joinWith as $config) {
list ($with, $eagerLoading, $joinType) = $config;
$this->joinWithRelations(new $this->modelClass, $with, $joinType);
if (is_array($eagerLoading)) {
foreach ($with as $name => $callback) {
if (is_integer($name)) {
if (!in_array($callback, $eagerLoading, true)) {
unset($with[$name]);
}
} elseif (!in_array($name, $eagerLoading, true)) {
unset($with[$name]);
}
} elseif (!in_array($name, $eagerLoading, true)) {
unset($with[$name]);
}
} elseif (!$eagerLoading) {
$with = [];
}
} elseif (!$eagerLoading) {
$with = [];
}
return $this->with($with);
$this->with($with);
}
}
/**

20
tests/unit/framework/db/ActiveRecordTest.php

@ -258,6 +258,16 @@ class ActiveRecordTest extends DatabaseTestCase
$this->assertTrue($orders[0]->isRelationPopulated('customer'));
$this->assertTrue($orders[1]->isRelationPopulated('customer'));
// inner join filtering, eager loading, conditions on both primary and relation
$orders = Order::find()->innerJoinWith([
'customer' => function ($query) {
$query->where(['tbl_customer.id' => 2]);
},
])->where(['tbl_order.id' => [1, 2]])->orderBy('tbl_order.id')->all();
$this->assertEquals(1, count($orders));
$this->assertEquals(2, $orders[0]->id);
$this->assertTrue($orders[0]->isRelationPopulated('customer'));
// inner join filtering without eager loading
$orders = Order::find()->innerJoinWith([
'customer' => function ($query) {
@ -270,6 +280,16 @@ class ActiveRecordTest extends DatabaseTestCase
$this->assertFalse($orders[0]->isRelationPopulated('customer'));
$this->assertFalse($orders[1]->isRelationPopulated('customer'));
// inner join filtering without eager loading, conditions on both primary and relation
$orders = Order::find()->innerJoinWith([
'customer' => function ($query) {
$query->where(['tbl_customer.id' => 2]);
},
], false)->where(['tbl_order.id' => [1, 2]])->orderBy('tbl_order.id')->all();
$this->assertEquals(1, count($orders));
$this->assertEquals(2, $orders[0]->id);
$this->assertFalse($orders[0]->isRelationPopulated('customer'));
// join with via-relation
$orders = Order::find()->innerJoinWith('books')->orderBy('tbl_order.id')->all();
$this->assertEquals(2, count($orders));

Loading…
Cancel
Save