Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
83fda4b
Merge pull request #1 from yiisoft/master
rhertogh Jul 30, 2015
5231894
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh Jan 24, 2020
e388dfc
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh Jul 16, 2020
6b56e2c
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh Aug 20, 2020
1676da7
Merge branch 'master' of https://github.com/yiisoft/yii2 into master
rhertogh Oct 31, 2020
accf01e
Merge branch 'master' of https://github.com/yiisoft/yii2 into master
rhertogh May 23, 2021
8856e22
Merge branch 'master' of https://github.com/yiisoft/yii2 into master
rhertogh Jun 2, 2021
22f4a41
Merge branch 'master' of https://github.com/yiisoft/yii2 into master
rhertogh Jun 23, 2021
6548c45
Merge branch 'master' of https://github.com/yiisoft/yii2 into master
rhertogh Aug 15, 2021
315bda2
Merge branch 'master' of https://github.com/yiisoft/yii2 into master
rhertogh Sep 13, 2021
3db5c78
Merge branch 'master' of https://github.com/yiisoft/yii2 into master
rhertogh Sep 15, 2021
c164bea
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh Jan 17, 2022
1b5c680
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh May 16, 2022
91a8582
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh Jun 13, 2022
c1b3877
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh Oct 27, 2022
43b4425
Merge branch 'master' of https://github.com/yiisoft/yii2
rhertogh Apr 10, 2023
9333a3a
Initial setup for "via joined" support
rhertogh Apr 10, 2023
368096d
#19805 Added test for ActiveQuery viaJoined methods
rhertogh May 1, 2023
c4c3b98
selecting all columns in ActiveQuery Test for MSSql
rhertogh May 1, 2023
638e924
Merge branch 'master' into via_joined
rhertogh May 1, 2023
6c7ba79
#19805 Using distinct instead of group by for ActiveQuery via join
rhertogh May 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 112 additions & 1 deletion framework/db/ActiveQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace yii\db;

use yii\base\InvalidCallException;
use yii\base\InvalidConfigException;

/**
Expand Down Expand Up @@ -98,6 +99,9 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/
public $joinWith;

protected $useJoinForVia = false;

protected $viaAppliedByJoin = false;

/**
* Constructor.
Expand Down Expand Up @@ -163,7 +167,69 @@ public function prepare($builder)
// lazy loading of a relation
$where = $this->where;

if ($this->via instanceof self) {
if (
$this->useJoinForVia()
&& ($this->via instanceof self
|| is_array($this->via)
)
) {
/* @var $viaQuery ActiveQuery */
$viaQuery = ($this->via instanceof self) ? $this->via : $this->via[1];

list(, $tableAlias) = $this->getTableNameAndAlias();
if (strpos($tableAlias, '{{') === false) {
$tableAlias = '{{' . $tableAlias . '}}';
}

if (empty($this->select)) {
$this->select = ["$tableAlias.*"];
}

if (empty($this->groupBy) && !$this->distinct) {
$this->distinct();
}

if (!$this->viaAppliedByJoin) {
// Setup first 'via' relation in the chain based on initial link.
$previousRelation = $this;
$previousLink = $this->link;
while ($viaQuery) { // Loop over each 'via' chain while we got links.
if ($viaQuery->via) { // Check if we've got another 'via' link.
$nextViaQuery = ($viaQuery->via instanceof self) ? $viaQuery->via : $viaQuery->via[1];
$viaQuery->via = null;
} else {
// End of 'via' chain
$nextViaQuery = null;

// Get table alias for final junction table
list(, $viaAlias) = $viaQuery->getTableNameAndAlias();
if (strpos($viaAlias, '{{') === false) {
$viaAlias = '{{' . $viaAlias . '}}';
}
// Apply primary model relation as additional inner join `on` conditions for the final junction table.
foreach ($viaQuery->link as $primaryColumn => $viaColumn) {
$viaQuery->andOnCondition([
"$viaAlias.[[$primaryColumn]]" => $this->primaryModel->getAttribute($viaColumn)
]);
}
}

$nextLink = $viaQuery->link; // Store the current 'via' link for the next link.
$viaQuery->link = array_flip($previousLink); // Use the inverted previous link as the current one.

// Join the 'via' link on the previous link
$this->joinWithRelation($previousRelation, $viaQuery, 'INNER JOIN');

// Setup data for next iteration
$previousRelation = $viaQuery;
$viaQuery = $nextViaQuery;
$previousLink = $nextLink;
}

// Prevent duplicate application of the join(s) e.g. for ActiveDataProvider
$this->viaAppliedByJoin = true;
}
} elseif ($this->via instanceof self) {
// via junction table
$viaModels = $this->via->findJunctionRows([$this->primaryModel]);
$this->filterByModels($viaModels);
Expand Down Expand Up @@ -761,6 +827,33 @@ public function orOnCondition($condition, $params = [])
return $this;
}

public function viaByJoin($viaByJoin = true)
{
if (!$viaByJoin) {
if ($this->viaAppliedByJoin) {
throw new InvalidCallException('`viaByJoin` can not be disabled after it has been applied.');
}
if ($this->via instanceof self && !empty($this->via->via)) {
throw new InvalidCallException('`viaByJoin` can not be disabled when using multiple "via tables".');
}
}

$this->useJoinForVia = $viaByJoin;
return $this;
}

public function useJoinForVia()
{
return $this->useJoinForVia;
}

public function viaJoined($relationName, callable $callable = null)
{
return $this
->viaByJoin()
->via($relationName, $callable);
}

/**
* Specifies the junction table for a relational query.
*
Expand Down Expand Up @@ -801,6 +894,24 @@ public function viaTable($tableName, $link, callable $callable = null)
return $this;
}

public function viaJoinedTable($tableName, $link, callable $callable = null)
{
return $this
->viaByJoin()
->viaTable($tableName, $link, $callable);
}

public function viaJoinedTables($links, callable $callable = null)
{
$this->viaByJoin();
$query = $this;
foreach ($links as $tableName => $link) {
$query->viaTable($tableName, $link, $callable);
$query = $query->via;
}
return $this;
}

/**
* Define an alias for the table defined in [[modelClass]].
*
Expand Down
1 change: 1 addition & 0 deletions framework/db/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ protected function queryScalar($selectExpression, $db)
&& empty($this->groupBy)
&& empty($this->having)
&& empty($this->union)
&& (!($this instanceof ActiveQuery) || !$this->useJoinForVia())
) {
$select = $this->select;
$order = $this->orderBy;
Expand Down
Loading