关联统计
@access public
@param string|array $relation 关联方法名
@param bool         $subQuery 是否使用子查询
@return $this
513197
public function withCount($relation, $subQuery = true)
    {
        if (!$subQuery) {
            $this->options['with_count'] = $relation;
        } else {
            $relations = is_string($relation) ? explode(',', $relation) : $relation;
            if (!isset($this->options['field'])) {
                $this->field('*');
            }
            foreach ($relations as $key => $relation) {
                $closure = false;
                if ($relation instanceof \Closure) {
                    $closure  = $relation;
                    $relation = $key;
                }
                $relation = Parse::parseName($relation, 1, false);
                $count    = '(' . (new $this->model)->$relation()->getRelationCountQuery($closure) . ')';
                $this->field([$count => Parse::parseName($relation) . '_count']);
            }
        }
        return $this;
    }
1140652
protected function eagerlyOneToMany($where, $relation, $subRelation = '', $closure = null)
    {
        $foreignKey = $this->foreignKey;

        $this->query->removeWhereField($this->foreignKey);

        // 预载入关联查询 支持嵌套预载入
        if ($closure) {
            $closure($this->query);
        }

        $list = $this->query->where($where)->with($subRelation)->select();

        // 组装模型数据
        $data = [];

        foreach ($list as $set) {
            $data[$set->$foreignKey][] = $set;
        }

        return $data;
    }
1185749
public function withSum($relation, $field, $subQuery = true)
    {
        return $this->withAggregate($relation, 'sum', $field, $subQuery);
    }
244869
public function joinSubquery($subquery, $on, $joinType = Joins::INNER)
    {
        return $this->join($subquery, $on, $joinType);
    }
1298592
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $join = false)
    {
        if ($join || 0 == $this->eagerlyType) {
            // 模型JOIN关联组装
            foreach ($resultSet as $result) {
                $this->match($this->model, $relation, $result);
            }
        } else {
            // IN查询
            $this->eagerlySet($resultSet, $relation, $subRelation, $closure);
        }
    }
124705
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
    {
        $morphType = $this->morphType;
        $morphKey  = $this->morphKey;
        $type      = $this->type;
        $range     = [];

        foreach ($resultSet as $result) {
            $pk = $result->getPk();
            // 获取关联外键列表
            if (isset($result->$pk)) {
                $range[] = $result->$pk;
            }
        }

        if (!empty($range)) {
            $data = $this->eagerlyMorphToOne([
                [$morphKey, 'in', $range],
                [$morphType, '=', $type],
            ], $relation, $subRelation, $closure);

            // 关联属性名
            $attr = Db::parseName($relation);

            // 关联数据封装
            foreach ($resultSet as $result) {
                if (!isset($data[$result->$pk])) {
                    $relationModel = null;
                } else {
                    $relationModel = $data[$result->$pk];
                    $relationModel->setParent(clone $result);
                    $relationModel->isUpdate(true);
                }

                $result->setRelation($attr, $relationModel);
            }
        }
    }
1266086
protected function subquery(Subquery $subquery, bool $enclose = true): string
	{
		$query = $subquery->getQuery();

		if($query instanceof Closure)
		{
			$builder = $query;

			$query = $this->query->newInstance()->inSubqueryContext();

			$builder($query);
		}

		$query = $query->getCompiler()->select();

		$this->params = array_merge($this->params, $query['params']);

		if($enclose)
		{
			$query['sql'] = '(' . $query['sql'] . ')';
		}

		if(($alias = $subquery->getAlias()) !== null)
		{
			$query['sql'] .= ' AS ' . $this->escapeIdentifier($alias);
		}

		return $query['sql'];
	}
1263201
public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
    {
        $entity = $this->mapper->newInstance();

        $relation = $this->getHasRelationQuery($relation, $entity);

        $query = $relation->getRelationCountQuery($relation->getRelatedMapper()->getQuery(), $this);

        if ($callback) {
            call_user_func($callback, $query);
        }

        return $this->addHasWhere($query, $relation, $operator, $count, $boolean);
    }
911460
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
    {
        $morphKey  = $this->morphKey;
        $morphType = $this->morphType;
        $range     = [];

        foreach ($resultSet as $result) {
            // 获取关联外键列表
            if (!empty($result->$morphKey)) {
                $range[$result->$morphType][] = $result->$morphKey;
            }
        }

        if (!empty($range)) {
            // 关联属性名
            $attr = Db::parseName($relation);

            foreach ($range as $key => $val) {
                // 多态类型映射
                $model = $this->parseModel($key);
                $obj   = new $model;
                $pk    = $obj->getPk();
                $list  = $obj->all($val, $subRelation);
                $data  = [];

                foreach ($list as $k => $vo) {
                    $data[$vo->$pk] = $vo;
                }

                foreach ($resultSet as $result) {
                    if ($key == $result->$morphType) {
                        // 关联模型
                        if (!isset($data[$result->$morphKey])) {
                            $relationModel = null;
                        } else {
                            $relationModel = $data[$result->$morphKey];
                            $relationModel->setParent(clone $result);
                            $relationModel->isUpdate(true);
                        }

                        $result->setRelation($attr, $relationModel);
                    }
                }
            }
        }
    }
3624
public function getRelation($subRelation = '', $closure = null)
    {
        if ($closure) {
            $closure($this->query);
        }

        $result = $this->buildQuery()->relation($subRelation)->select();
        $this->hydratePivot($result);

        return $result;
    }
909238
public function _setType(string $type, array $relation)
    {
        $this->type = $type;
        $this->relation = $relation;
        return $this;
    }
122606
public function getRelation($subRelation = '', $closure = null)
    {
        $morphKey  = $this->morphKey;
        $morphType = $this->morphType;

        // 多态模型
        $model = $this->parseModel($this->parent->$morphType);

        // 主键数据
        $pk = $this->parent->$morphKey;

        $relationModel = (new $model)->relation($subRelation)->find($pk);

        if ($relationModel) {
            $relationModel->setParent(clone $this->parent);
        }

        return $relationModel;
    }
707998
public function addRelationSelectColumns($relation)
    {
        $join = $this->joins[$relation];
        $join->getTableMap()->addSelectColumns($this, $join->getRelationAlias());

        return $this;
    }
876924
protected function getRelationCondition($relation, $value)
    {
        /** @var \yii\db\ActiveRecord $relationClass */
        $relationClass = $relation->modelClass;
        if ($relation->via !== null) {
            /* @var $viaRelation \yii\db\ActiveQuery */
            $viaRelation = is_array($relation->via) ? $relation->via[1] : $relation->via;
            /** @var \yii\db\ActiveRecord $viaClass */
            $viaClass = $viaRelation->modelClass;
            $subquery = (new Query)
                ->select(array_map(function ($key) {
                    return 'j.' . $key;
                }, array_keys($viaRelation->link)))
                ->from(['t' => $relationClass::tableName()])
                ->innerJoin(['j' => $viaClass::tableName()], implode(' AND ', array_map(function ($leftKey, $rightKey) {
                    return 't.' . $leftKey .' = j.' . $rightKey;
                }, array_keys($relation->link), array_values($relation->link))))
                ->where(['IN', array_map(function ($key) {
                    return 't.' . $key;
                }, $relationClass::primaryKey()), $value]);
            $linkKeys = array_values($viaRelation->link);
        } else {
            $subquery = (new Query)
                ->select(array_keys($relation->link))
                ->from(['t' => $relationClass::tableName()])
                ->where(['IN', array_map(function ($key) {
                    return 't.' . $key;
                }, $relationClass::primaryKey()), $value]);
            $linkKeys = array_values($relation->link);
        }
        return ['IN', array_map(function ($key) {
            return 't.' . $key;
        }, $linkKeys), $subquery];
    }
97818
public function removeRel($relation)
        {
            if (isset($this->_rel[$relation])) {
                unset($this->_rel[$relation]);
            }

            return $this;
        }
590149
public function buildDeleteRelationQuery($relation, $entity) {
        $query = "DELETE FROM " . $relation->getTable() . " ";
        $query .= "WHERE " . $relation->getForeignColumn() . " = '" . $entity->getId() . "';";
        return $query;
    }
1113277
public function related($relation, $column, $operator = null, $value = null, $boolean = 'and')
    {
        if ($column instanceof \Closure) {
            return $this->addRelated($relation, $column);
        }

        // If there is no value it is a where = ? query and we set the appropriate params
        if ($value === null) {
            $value = $operator;
            $operator = '=';
        }

        return $this->addRelated($relation, function ($query) use ($column, $operator, $value, $boolean) {
            return $query->where($column, $operator, $value, $boolean);
        });
    }