根据关联条件查询当前模型
@access public
@param  string  $relation 关联方法名
@param  mixed   $operator 比较操作符
@param  integer $count    个数
@param  string  $id       关联表的统计字段
@param  string  $joinType JOIN类型
@return Query
342687
public static function has($relation, $operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
    {
        $relation = (new static())->$relation();

        if (is_array($operator) || $operator instanceof \Closure) {
            return $relation->hasWhere($operator);
        }

        return $relation->has($operator, $count, $id, $joinType);
    }
395929
public function eagerlyResult(&$result, $relation, $subRelation, $closure)
    {
        $localKey = $this->localKey;

        if (isset($result->$localKey)) {
            $pk    = $result->$localKey;
            $where = [
                [$this->foreignKey, '=', $pk],
            ];
            $data = $this->eagerlyOneToMany($where, $relation, $subRelation, $closure);

            // 关联数据封装
            if (!isset($data[$pk])) {
                $data[$pk] = [];
            }

            foreach ($data[$pk] as &$relationModel) {
                $relationModel->setParent(clone $result);
            }

            $result->setRelation(Db::parseName($relation), $this->resultSetBuild($data[$pk]));
        }
    }
499176
public function addJoinColumn(
        $relation,
        $joinColumn = null,
        $referenceColumn = null,
        $nullable = false,
        $unique = false,
        $onDelete = null,
        $columnDefinition = null
    ) {
        $joinColumn = new JoinColumn(
            $this->getNamingStrategy(),
            $relation,
            $joinColumn,
            $referenceColumn,
            $nullable,
            $unique,
            $onDelete,
            $columnDefinition
        );

        $this->pushJoinColumn($joinColumn);

        return $this;
    }
1158935
public function join($linkTableName, $relation, $fields = '*', $where = [], $orderBy = ''): Result
    {
        // 生成关联表模型对象
        $table = $this->makeTable($linkTableName);

        // 生成本表关联字段与关联表关联字段
        list ($field, $linkField) = $this->relation($relation);

        // 生成本表关联字段的所有值
        $keys = $this->getMapKeys($field);
        if (!$keys) {
            return $this;
        }

        // 生成关联表查询条件
        // $where [] = $table->markField ( $linkField ) . ' in ("' . join ( '","', $keys ) . '") ';
        $where[$linkField . ' in'] = $keys;

        // 关联表查询结果
        $linkData = $table->select($this->append($fields, $linkField), $where, $orderBy)
            ->all();

        // 生成以关联表关联字段值为键的数组
        $linkResult = [];
        foreach ($linkData as $row) {
            $key = $row[$linkField];
            if (!array_key_exists($key, $linkResult)) {
                $linkResult[$key] = [];
            }
            $linkResult[$key][] = $row;
        }

        // 转换每个值对应的结果为结果集对象
        foreach ($linkResult as $k => $v) {
            $linkResult[$k] = new Result($linkTableName, $v);
        }

        // 为本表每行数据补充字段
        foreach ($this->data as $key => $row) {

            // 如果没有对应的关联,则不扩展
            if (array_key_exists($row[$field], $linkResult)) {
                // 关联的记录
                $linkObj = $linkResult[$row[$field]];

                // 如果本表已经有此字段,则不扩展
                if (!array_key_exists($table->name(), $row)) {
                    $row[$table->alias()] = $linkObj;
                }

                $this->data[$key] = $row;
            }
        }

        $this->row2Obj();
        return $this;
    }
1185770
public function relationIsJoined($relation)
    {
        if ($this->_joinedTables === null) {
            $this->_joinedTables = $this->getJoinedTables();
        }

        return in_array($this->getRelatedTable($relation), $this->_joinedTables, true);
    }
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);
        });
    }
310915
private function getJoin(\ReflectionProperty $property, $type = Join::class, $exception = true)
    {
        /** @var Join|JoinTable $join */
        $join = $this->reader->getPropertyAnnotation($property, $type);
        if ($exception && ($join === null || ! $join instanceof $type)) {
            throw new RelationException("Relation in '".$property->getDeclaringClass()->getName()."' -> '".$property->getName()."' should have @$type annotation!"); // @codeCoverageIgnore
        }
        if ($exception && $type === Join::class && ($join->column === null || $join->targetColumn === null)) {
            throw new RelationException("Join in '".$property->getDeclaringClass()->getName()."' -> '".$property->getName()."' should have the local column and targetColumn filled in!"); // @codeCoverageIgnore
        }
        if ($exception && $type === JoinTable::class && ($join->name == "" || ! $join->column instanceof JoinColumn || ! $join->targetColumn instanceof JoinColumn)) {
            throw new RelationException("JoinTable in '".$property->getDeclaringClass()->getName()."' -> '".$property->getName()."' should have a table name and 2 join columns in column and targetColumn!"); // @codeCoverageIgnore
        }
        return $join;
    }
1272224
protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure)
    {
        $localKey   = $this->localKey;
        $foreignKey = $this->foreignKey;

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

        if (!empty($range)) {
            $this->query->removeWhereField($foreignKey);

            $data = $this->eagerlyWhere([
                [$foreignKey, 'in', $range],
            ], $foreignKey, $relation, $subRelation, $closure);

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

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

                if (!empty($this->bindAttr)) {
                    // 绑定关联属性
                    $this->bindAttr($relationModel, $result, $this->bindAttr);
                } else {
                    // 设置关联属性
                    $result->setRelation($attr, $relationModel);
                }
            }
        }
    }
105904
private function createRelation($relation): array
    {
        // 处理数据形式
        if (is_array($relation)) {
            foreach ($relation as $k => $v) {
                if (is_numeric($k)) {
                    return $v;
                }
                return [$k, $v];
            }
        }

        // 字符串形式
        if (!is_string($relation)) {
            trigger_error('关联关系错误:' . json($relation), E_USER_ERROR);
        }

        // 分解关联键
        $matches = explode('=', $relation);

        // 如果只指明了一个字段,默认后一个字段为_id/id(表的主键)
        if (count($matches) == 1) {
            return [$relation, 'id'];
        }

        // 返回两个关联键
        return $matches;
    }
1285819
public static function buildRelationQuery($entity, Relation $relation) {
        $relQuery = "";
        $getid = "getId";
        if ($relation->getCardinality() == Relation::$manyToMany) {
            $m = "get" . $relation->getName();
            $relQuery .= "INSERT INTO " . $relation->getTable() . " (" . $relation->getLocalColumn() . ", " . $relation->getForeignColumn() . ") ";
            $relQuery .= "VALUES (:" . $relation->getLocalColumn() . ", :" . $relation->getForeignColumn() . ");";
        }
        if ($relation->getCardinality() == Relation::$oneToMany) {
            $relMapper = MapperBuilder::buildFromName($this->mapping, $relation->getEntity());
            $m = "get" . $relation->getName();
            foreach ($entity->$m() as $rel) {
                $setid = "set" . $relMapper->getNameForColumn($relation->getForeignColumn());
                $rel->$setid($entity->$getid());
                $relQuery .= $this->buildInsertQuery($rel);
            }
        }


        return $relQuery;
    }
793763
public function getCursor($sql, $bind = [], $master = false, $model = null, $condition = null, $relation = null)
    {
        $this->initConnect($master);

        // 记录SQL语句
        $this->queryStr = $sql;

        $this->bind = $bind;

        Db::$queryTimes++;

        // 调试开始
        $this->debug(true);

        // 预处理
        $this->PDOStatement = $this->linkID->prepare($sql);

        // 是否为存储过程调用
        $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);

        // 参数绑定
        if ($procedure) {
            $this->bindParam($bind);
        } else {
            $this->bindValue($bind);
        }

        // 执行查询
        $this->PDOStatement->execute();

        // 调试结束
        $this->debug(false, '', $master);

        // 返回结果集
        while ($result = $this->PDOStatement->fetch($this->fetchType)) {
            if ($model) {
                $instance = $model->newInstance($result, $condition);

                if ($relation) {
                    $instance->relationQuery($relation);
                }

                yield $instance;
            } else {
                yield $result;
            }
        }
    }
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;
    }
864160
protected function whereHandler($key, $operator = null, $value = null, $joiner = 'AND')
    {
        $key = $this->addTablePrefix($key);
        $this->statements['wheres'][] = compact('key', 'operator', 'value', 'joiner');
        return $this;
    }
176321
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
    {
        $localKey   = $this->localKey;
        $foreignKey = $this->foreignKey;

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

        if (!empty($range)) {
            // 查询关联数据
            $data = $this->eagerlyManyToMany([
                ['pivot.' . $localKey, 'in', $range],
            ], $relation, $subRelation, $closure);

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

            // 关联数据封装
            foreach ($resultSet as $result) {
                if (!isset($data[$result->$pk])) {
                    $data[$result->$pk] = [];
                }

                $result->setRelation($attr, $this->resultSetBuild($data[$result->$pk]));
            }
        }
    }
1265109
public function join($table, $on = null, $where = null, $binds = [], $type = 'LEFT')
    {
        if ($table instanceof Relation) {
            if (is_only_callable($on)) {
                /**
                 * Is this needed?
                 */
                Reflect::call($on, [$table, $table->getQuery()]);
            }

            $table->mergeToQuery($this->getQuery());
        } elseif ($table instanceof Entity) {
            $query = $table->getQuery();

            $sql = $query->buildSQL();

            $this->getQuery()->join(
                $type . ' JOIN (' . $sql . ') AS `' . $where . '` ON (' .
                (strpos($on, '(') ? '' : ($where . '.')) . $on . ')',
                null,
                null,
                $query->buildBinds()
            );
        } else {
            $this->getQuery()->join($table, $on, $where, $binds);
        }

        return $this;
    }
90674
function join($relation, $expr = null, $mode = Join::INNER)
    {
        if (null !== $expr) {
            $expr = new On(new AndX(array($expr)));
        }

        $join = new Join($relation, $expr);
        $join->mode = $mode;

        $this->nodes->source->right[] = $join;
        return $this;
    }
653258
public function addJoin(Expression $foreign, Statement\Where $on, $joinType = Joins::INNER)
    {
        $this->getJoinStatement()->add($foreign, $on, $joinType);
        
        return $this;
    }