获取Join表名及别名 支持
['prefix_table或者子查询'=>'alias'] 'prefix_table alias' 'table alias'
@access public
@param array|string $join
@param $alias
@return array|string
190565
protected function getJoinTable($join, &$alias = null)
    {
        // 传入的表名为数组
        if (is_array($join)) {
            $table = $join[0];
            $alias = $join[1];
        } else {
            $join = trim($join);
            if (false !== strpos($join, '(')) {
                // 使用子查询
                $table = $join;
            } else {
                $prefix = $this->prefix;
                if (strpos($join, ' ')) {
                    // 使用别名
                    list($table, $alias) = explode(' ', $join);
                } else {
                    $table = $join;
                    if (false === strpos($join, '.') && 0 !== strpos($join, '__')) {
                        $alias = $join;
                    }
                }
                if ($prefix && false === strpos($table, '.') && 0 !== strpos($table, $prefix) && 0 !== strpos($table, '__')) {
                    $table = $this->getTable($table);
                }
            }
        }
        if (isset($alias)) {
            if (isset($this->options['alias'][$table])) {
                $table = $table . '@think' . uniqid();
            }
            $table = [$table => $alias];
            $this->alias($table);
        }
        return $table;
    }
480806
public function join(array $join = [], $table = '')
    {
        $string = '';

        foreach ($join as $type => $value) {
            $string .= sprintf("%s %s ON %s.%s = %s.%s", $type, $value[0], $value[0], $value[1], $table, $value[2]);
        }

        return $string;
    }
1134164
public function innerJoin($table, $alias = null, $on = null)
    {
        return $this->join($table, $alias, $on, 'INNER JOIN');
    }
1010601
protected function prepareJoins($joins) {
        $_joins = [];
        if ($joins) {
            foreach ($joins as $join) {
                $table     = $this->dialect->getTableName($join [0]);
                $alias     = empty ($join [3]) ? $table : $join [3];
                $_joins [] = [$table, $join [1], $join [2], $alias];
            }
        }

        return $_joins;
    }
783531
public function join($join,$type='INNER') {
        $prefix =   $this->tablePrefix;
        if(is_array($join)) {
            foreach ($join as $key=>&$_join){
                $_join  =   preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $_join);
                $_join  =   false !== stripos($_join,'JOIN')? $_join : $type.' JOIN ' .$_join;
            }
            $this->options['join']      =   $join;
        }elseif(!empty($join)) {
            //将__TABLE_NAME__字符串替换成带前缀的表名
            $join  = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $join);
            $this->options['join'][]    =   false !== stripos($join,'JOIN')? $join : $type.' JOIN '.$join;
        }
        return $this;
    }
1286180
protected function processJoin(Join $join, $context): Join
    {
        $table = $this->processTable($join->table, $context);
        $criteria = [];
        foreach ($join->criteria as $index => $criterion) {
            $criteria[$index] = $this->processCriterion($criterion, $context);
        }

        if ($table === $join->table && $criteria === $join->criteria) {
            return $join;
        } else {
            return new Join($join->type, $table, $join->tableAlias, $criteria);
        }
    }
139236
public function leftJoin($table, $alias = null, $on = null)
    {
        return $this->join($table, $alias, $on, 'LEFT JOIN');
    }
343485
public function addJoin($join)
    {
        if (!$this->joins->contains($join)) {
            $this->joins[] = $join;
        }

        return $this;
    }
422119
public static function render(SQL\Join $join)
    {
        $condition = $join->getCondition();
        $table = $join->getTable();

        return Compiler::expression(array(
            $join->getType(),
            'JOIN',
            $table instanceof SQL\Aliased ? Aliased::render($table) : $table,
            is_array($condition) ? self::renderArrayCondition($condition) : $condition,
        ));
    }
463872
public function join($table, $condition = null, $alias = null, $type = null)
    {
        if (strpos($condition, '[') === false && strpos($condition, '(') === false) {
            $condition = (string)preg_replace('#\w+#', '[\\0]', $condition);
        }

        if (is_string($table) && strpos($table, '\\') !== false) {
            /** @var \ManaPHP\Model $model */
            $model = $this->_di->getShared($table);
            $table = $model->getSource($this->_bind);
        }

        $this->_joins[] = [$table, $condition, $alias, $type];

        return $this;
    }
19518
public static function getJoinAlias(Join $join): string
    {
        @trigger_error(sprintf('The use of "%s::getJoinAlias()" is deprecated since 2.3 and will be removed in 3.0. Use "%s::getAlias()" directly instead.', __CLASS__, Join::class), E_USER_DEPRECATED);

        return $join->getAlias();
    }
1032922
public function selectFields($fields, $tableAlias, &$join)
    {
        //
        if (!$fields) {
            return '*';
        } elseif (is_string($fields)) {
            return $fields;
        } elseif (!is_array($fields)) {
            static::error('selectFields require array');
        }

        //
        $join = '';

        //
        $aliasTable = [];

        //
        $selectFields = [];

        //
        foreach ($fields as $field => $definition) {
            if (is_numeric($field)) {
                $field = $definition;
                $definition = null;
            }

            //
            if (!$definition) {
                $selectFields[] = $this->selectFieldsSingletoneField(
                    $field,
                    $tableAlias
                );
                continue;
            }

            //
            if (is_string($definition)) {
                $selectFields[] = $definition.' AS '.$field;
                continue;
            }

            //
            if (is_array($definition)) {
                $class = $definition['Class'];

                //
                $aliasTable[$class] = isset($aliasTable[$class])
                                    ? $aliasTable[$class] + 1
                                    : 1;

                //
                $joinAlias = $aliasTable[$class] > 1
                           ? $class.''.$aliasTable[$class]
                           : $class;

                //
                $joinTable = $definition['Table'];

                //
                $joinKey = $joinAlias.'.'.$definition['JoinKey'];

                //
                $fieldFrom = $definition['FieldFrom'];

                if ($fieldFrom == '__FIELD__') {
                    $fieldFrom = $field;
                }

                //
                $join .= " LEFT JOIN {$joinTable} AS {$joinAlias}"
                       ." ON {$joinKey} = {$fieldFrom}";

                if (is_array($definition['FieldTo'])) {
                    foreach ($definition['FieldTo'] as $nextFieldTo) {
                        $fieldAlias = $field.'__'.$nextFieldTo;
                        $fieldTo = $joinAlias.'.'.$nextFieldTo;
                        $selectFields[] = $fieldTo.' AS '.$fieldAlias;
                    }
                }

                continue;
            }
        }

        return implode(', ', $selectFields);
    }
167080
public function leftJoin($fromAlias, $join, $alias, $condition = null)
    {
        $this->_dbPending[] = [
            'name' => 'leftJoin',
            'args' => [
                $fromAlias,
                $join,
                $alias,
                $condition
            ],
        ];

        return $this;
    }
244137
public function alias($alias)
    {
        if (is_array($alias)) {
            foreach ($alias as $key => $val) {
                $this->options['alias'][$key] = $val;
            }
        } else {
            if (isset($this->options['table'])) {
                $table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table'];
                if (false !== strpos($table, '__')) {
                    $table = $this->parseSqlTable($table);
                }
            } else {
                $table = $this->getTable();
            }

            $this->options['alias'][$table] = $alias;
        }
        return $this;
    }
322761
public function addTable($alias, $table, $condition = null, $joinType = 'LEFT', $prefix = null)
    {
        $tableStorage = [];

        $tableStorage['name'] = $table;
        $tableStorage['join'] = strtoupper($joinType);

        $condition = trim((string) new QueryElement('', (array) $condition, ' AND '));

        if (!$condition) {
            $tableStorage['join'] = 'FROM';
        }

        // Remove too many spaces
        $condition = preg_replace('/\s(?=\s)/', '', $condition);

        $tableStorage['condition'] = $condition;
        $tableStorage['prefix'] = $prefix;

        $this->tables[$alias] = $tableStorage;

        return $this;
    }
853454
private static function getExistingJoin(QueryBuilder $queryBuilder, string $alias, string $association, string $originAlias = null): ?Join
    {
        $parts = $queryBuilder->getDQLPart('join');
        $rootAlias = $originAlias ?? $queryBuilder->getRootAliases()[0];

        if (!isset($parts[$rootAlias])) {
            return null;
        }

        foreach ($parts[$rootAlias] as $join) {
            /** @var Join $join */
            if (sprintf('%s.%s', $alias, $association) === $join->getJoin()) {
                return $join;
            }
        }

        return null;
    }
61476
protected function _buildJoins($schemas, $aliases)
    {
        $joins = [];
        foreach ($this->_parts['joins'] as $value) {
            $table = $value['join'];
            $on = $value['on'];
            $type = $value['type'];
            $join = [strtoupper($type), 'JOIN'];
            $join[] = $this->dialect()->name($table);

            if ($on) {
                $join[] = 'ON';
                $join[] = $this->dialect()->conditions($on, compact('schemas', 'aliases'));
            }

            $joins[] = join(' ', $join);
        }
        return $joins ? ' ' . join(' ', $joins) : '';
    }