mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-04 06:37:55 +08:00
Draft implementation of ActiveQuery::joinWith().
This commit is contained in:
@ -143,4 +143,141 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||
}
|
||||
return $db->createCommand($sql, $params);
|
||||
}
|
||||
|
||||
public function joinWith($with, $eagerLoading = true, $joinType = 'INNER JOIN')
|
||||
{
|
||||
$with = (array)$with;
|
||||
$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]);
|
||||
}
|
||||
}
|
||||
$this->with($with);
|
||||
} elseif ($eagerLoading) {
|
||||
$this->with($with);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActiveRecord $model
|
||||
* @param array $with
|
||||
* @param string|array $joinType
|
||||
*/
|
||||
private function joinWithRelations($model, $with, $joinType)
|
||||
{
|
||||
$relations = [];
|
||||
|
||||
foreach ($with as $name => $callback) {
|
||||
if (is_integer($name)) {
|
||||
$name = $callback;
|
||||
$callback = null;
|
||||
}
|
||||
|
||||
$primaryModel = $model;
|
||||
$parent = $this;
|
||||
$prefix = '';
|
||||
while (($pos = strpos($name, '.')) !== false) {
|
||||
$childName = substr($name, $pos + 1);
|
||||
$name = substr($name, 0, $pos);
|
||||
$fullName = $prefix === '' ? $name : "$prefix.$name";
|
||||
if (!isset($relations[$fullName])) {
|
||||
$relations[$fullName] = $relation = $primaryModel->getRelation($name);
|
||||
$this->joinWithRelation($parent, $relation, $this->getJoinType($joinType, $fullName));
|
||||
} else {
|
||||
$relation = $relations[$fullName];
|
||||
}
|
||||
$primaryModel = new $relation->modelClass;
|
||||
$parent = $relation;
|
||||
$prefix = $fullName;
|
||||
$name = $childName;
|
||||
}
|
||||
|
||||
$fullName = $prefix === '' ? $name : "$prefix.$name";
|
||||
if (!isset($relations[$fullName])) {
|
||||
$relations[$fullName] = $relation = $primaryModel->getRelation($name);
|
||||
if ($callback !== null) {
|
||||
call_user_func($callback, $relation);
|
||||
}
|
||||
$this->joinWithRelation($parent, $relation, $this->getJoinType($joinType, $fullName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getJoinType($joinType, $name)
|
||||
{
|
||||
if (is_array($joinType) && isset($joinType[$name])) {
|
||||
return $joinType[$name];
|
||||
} else {
|
||||
return is_string($joinType) ? $joinType : 'INNER JOIN';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActiveQuery $query
|
||||
* @return string
|
||||
*/
|
||||
private function getQueryTableName($query)
|
||||
{
|
||||
if (empty($query->from)) {
|
||||
/** @var ActiveRecord $modelClass */
|
||||
$modelClass = $query->modelClass;
|
||||
return $modelClass::tableName();
|
||||
} else {
|
||||
return reset($query->from);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActiveQuery $parent
|
||||
* @param ActiveRelation $child
|
||||
* @param string $joinType
|
||||
*/
|
||||
private function joinWithRelation($parent, $child, $joinType)
|
||||
{
|
||||
$parentTable = $this->getQueryTableName($parent);
|
||||
$childTable = $this->getQueryTableName($child);
|
||||
if (!empty($child->link)) {
|
||||
$on = [];
|
||||
foreach ($child->link as $childColumn => $parentColumn) {
|
||||
$on[] = '{{' . $parentTable . "}}.[[$parentColumn]] = {{" . $childTable . "}}.[[$childColumn]]";
|
||||
}
|
||||
$on = implode(' AND ', $on);
|
||||
} else {
|
||||
$on = '';
|
||||
}
|
||||
$this->join($joinType, $childTable, $on);
|
||||
if (!empty($child->where)) {
|
||||
$this->andWhere($child->where);
|
||||
}
|
||||
if (!empty($child->having)) {
|
||||
$this->andHaving($child->having);
|
||||
}
|
||||
if (!empty($child->orderBy)) {
|
||||
$this->addOrderBy($child->orderBy);
|
||||
}
|
||||
if (!empty($child->groupBy)) {
|
||||
$this->addGroupBy($child->groupBy);
|
||||
}
|
||||
if (!empty($child->params)) {
|
||||
$this->addParams($child->params);
|
||||
}
|
||||
if (!empty($child->join)) {
|
||||
foreach ($child->join as $join) {
|
||||
$this->join[] = $join;
|
||||
}
|
||||
}
|
||||
if (!empty($child->union)) {
|
||||
foreach ($child->union as $union) {
|
||||
$this->union[] = $union;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user