Commit a2edf01c by Qiang Xue

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

parent 15b75941
...@@ -86,6 +86,10 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -86,6 +86,10 @@ class ActiveQuery extends Query implements ActiveQueryInterface
* @see onCondition() * @see onCondition()
*/ */
public $on; 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 ...@@ -232,6 +236,10 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/ */
protected function createCommandInternal($db) protected function createCommandInternal($db)
{ {
if (!empty($this->joinWith)) {
$this->buildJoinWith();
}
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass; $modelClass = $this->modelClass;
if ($db === null) { if ($db === null) {
...@@ -330,24 +338,32 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -330,24 +338,32 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/ */
public function joinWith($with, $eagerLoading = true, $joinType = 'LEFT JOIN') public function joinWith($with, $eagerLoading = true, $joinType = 'LEFT JOIN')
{ {
$with = (array)$with; $this->joinWith[] = [(array)$with, $eagerLoading, $joinType];
$this->joinWithRelations(new $this->modelClass, $with, $joinType); return $this;
}
if (is_array($eagerLoading)) { private function buildJoinWith()
foreach ($with as $name => $callback) { {
if (is_integer($name)) { foreach ($this->joinWith as $config) {
if (!in_array($callback, $eagerLoading, true)) { 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]); 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);
}
} }
/** /**
......
...@@ -258,6 +258,16 @@ class ActiveRecordTest extends DatabaseTestCase ...@@ -258,6 +258,16 @@ class ActiveRecordTest extends DatabaseTestCase
$this->assertTrue($orders[0]->isRelationPopulated('customer')); $this->assertTrue($orders[0]->isRelationPopulated('customer'));
$this->assertTrue($orders[1]->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 // inner join filtering without eager loading
$orders = Order::find()->innerJoinWith([ $orders = Order::find()->innerJoinWith([
'customer' => function ($query) { 'customer' => function ($query) {
...@@ -270,6 +280,16 @@ class ActiveRecordTest extends DatabaseTestCase ...@@ -270,6 +280,16 @@ class ActiveRecordTest extends DatabaseTestCase
$this->assertFalse($orders[0]->isRelationPopulated('customer')); $this->assertFalse($orders[0]->isRelationPopulated('customer'));
$this->assertFalse($orders[1]->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 // join with via-relation
$orders = Order::find()->innerJoinWith('books')->orderBy('tbl_order.id')->all(); $orders = Order::find()->innerJoinWith('books')->orderBy('tbl_order.id')->all();
$this->assertEquals(2, count($orders)); $this->assertEquals(2, count($orders));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment