Match the eagerly loaded results to their many parents.

@param array  $results
@param string $relation
@param string $type

@return array
347185
protected function matchOneOrMany(array $results, $relation, $type)
    {
        $entities = $this->getEager();

        $dictionary = $this->buildDictionary($entities);

        $cache = $this->parentMapper->getEntityCache();

        $host = $this;

        // Once we have the dictionary we can simply spin through the parent models to
        // link them up with their children using the keyed dictionary to make the
        // matching very convenient and easy work. Then we'll just return them.
        return array_map(function ($result) use ($dictionary, $cache, $type, $relation, $host) {
            $key = $result[$host->localKey];

            if (isset($dictionary[$key])) {
                $value = $host->getRelationValue($dictionary, $key, $type);

                $result[$relation] = $value;

                // TODO : Refactor This
                $cache->cacheLoadedRelationResult($key, $relation, $value, $this);
            } else {
                $result[$relation] = $type === 'many' ? $this->relatedMap->newCollection() : null;
            }

            return $result;
        }, $results);
    }
122477
protected function cacheRelation($results, $relation)
    {
        $cache = $this->parentMapper->getEntityCache();

        $cache->cacheLoadedRelationResult($this->parent->getEntityKeyName(), $relation, $results, $this);
    }
500619
def match(self, models, results, relation):
        
        return self.match_many(models, results, relation)
368064
protected function processResult(array $results)
    {
        foreach ($results as $key => $entity) {

            if (!empty($entity['data'])) {

                $entity['data'] = $this->decorator->denormalizeValue($entity['data']);
                $results[$key] = $entity;
            }
        }

        return $results;
    }
804301
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
    {
        $localKey = $this->localKey;
        $range    = [];

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

        if (!empty($range)) {
            $where = [
                [$this->foreignKey, 'in', $range],
            ];
            $data = $this->eagerlyOneToMany($where, $relation, $subRelation, $closure);

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

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

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

                $result->setRelation($attr, $this->resultSetBuild($data[$pk]));
            }
        }
    }
313878
protected function createSubAggregates($entities, string $relation): array
    {
        $aggregates = [];

        foreach ($entities as $entity) {
            $aggregates[] = $this->createSubAggregate($entity, $relation);
        }

        return $aggregates;
    }
310195
private function getDependencies(array $results)
    {
        $dependencies = [];
        $doubles = [];

        foreach ($results as $name => $result) {
            $type = $this->recursive ? Dependency::PROHIBITS : Dependency::DEPENDS;
            $dependency = Dependency::create($name, $type, $result);
            $unique = (string) $dependency->getLink();
            if (isset($doubles[$unique])) {
                continue;
            }
            $doubles[$unique] = true;
            $dependencies[] = $dependency;
        }

        return $dependencies;
    }
1057476
public function findRelation($entity, $relationName, $orderColumn = null, $orderType = null) {
        $this->load();
        $mapper = MapperBuilder::buildFromClassName($this->mapping, get_class($entity));
        $relation = $mapper->getRelation($relationName);
        $relationMapper = MapperBuilder::buildFromName($this->mapping, $relation->getEntity());

        $selectQuery = "SELECT tmain.* FROM `" . $relationMapper->getTable() . "` tmain ";
        $joinQuery = QueryBuilder::buildJoinRelationQuery($relation, "tmain", "j1");
        $whereQuery = "WHERE j1." . $relation->getLocalColumn() . " = '" . $entity->getId() . "'";

        $orderQuery = "";
        if (!is_null($orderColumn)) {
            $orderQuery .= "ORDER BY $orderColumn ";
            if (!is_null($orderType)) {
                $orderQuery .= "$orderType";
            } else {
                $orderQuery .= "ASC";
            }
        }

        $query = $selectQuery . $joinQuery . $whereQuery . $orderQuery;
        $queryResult = $this->getDataSource()->query($query);
        if ($queryResult) {
            $collection = new Collection($relationMapper->getClass(), $queryResult, $relationMapper);
        } else {
            $collection = new Collection($relationMapper->getClass(), array(), $relationMapper);
        }

        return $collection;
    }
263994
private function findRelations(string $class, array $relations): array
    {
        $results = [];

        foreach ($relations as $relation) {
            $definition = $relation->getDefinition();
            if ($definition->sourceContext()->getClass() === $class) {
                $name = $definition->getName();
                $types = [];

                $relationType = $definition->getType();
                if (in_array($relationType, [RecordEntity::MANY_TO_MANY, RecordEntity::HAS_MANY])) {
                    $types[] = $definition->getTarget() . '[]';
                } else {
                    $types[] = $definition->getTarget();
                }

                $types[] = $this->relationsConfig->relationClass($relationType,
                    RelationsConfig::ACCESS_CLASS);

                $options = $definition->getOptions();
                if (array_key_exists(RecordEntity::NULLABLE, $options)
                    && true === $options[RecordEntity::NULLABLE]
                ) {
                    $types[] = 'null';
                }

                $results[$name] = $types;
            }
        }

        return $results;
    }
804743
public function match(array $models, Collection $results, $relation)
    {
        $foreign = $this->foreignKey;

        $other = $this->otherKey;

        $dictionary = array();

        foreach ($results as $result) {
            $dictionary[$result->getAttribute($other)] = $result;
        }

        foreach ($models as $model) {
            if (isset($dictionary[$model->$foreign])) {
                $model->setRelation($relation, $dictionary[$model->$foreign]);
            }
        }

        return $models;
    }
207642
protected function fetchRelation(array $relation)
    {
        /* a relation is of the form
         * [$type, $foreign_class, $foreign_column, $column]
         */
        list($type, $foreign_class, $foreign_column, $column) = $relation;

        switch ($type) {
        case 'has_one':
            return $this->fetchOneToOne($foreign_class, $foreign_column, $column);
        case 'belongs_to':
            return $this->fetchOneToOne($foreign_class, $foreign_column, $column);
        case 'has_many':
            return $this->fetchOneToMany($foreign_class, $foreign_column, $column);
        default:
        }
    }
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);
        }
    }
1177635
public function getRelations($type = null) {
        if (!$type) {
            return $this->_relations;
        }

        $relations = [];

        foreach ($this->_relations as $relation) {
            if ($relation->getType() === $type) {
                $relations[$relation->getAlias()] = $relation;
            }
        }

        return $relations;
    }
260117
private function _getRelatedFks($data, $relation, $modelClass)
    {
        $fks = [];
        if (is_array($data)) {
            // Get the right link definition
            if ($relation->via instanceof BaseActiveRecord) {
                $link = $relation->via->link;
            } elseif (is_array($relation->via)) {
                list($viaName, $viaQuery) = $relation->via;
                $link = $viaQuery->link;
            } else {
                $link = $relation->link;
            }
            // search PK
            foreach ($modelClass::primaryKey() as $modelAttribute) {
                if (isset($data[$modelAttribute])) {
                    $fks[$modelAttribute] = $data[$modelAttribute];
                } elseif ($relation->multiple && !$relation->via) {
                    foreach ($link as $relatedAttribute => $relatedModelAttribute) {
                        if (!isset($data[$relatedAttribute]) && in_array($relatedAttribute, $modelClass::primaryKey())) {
                            $fks[$relatedAttribute] = $this->owner->{$relatedModelAttribute};
                        }
                    }
                } else {
                    $fks = [];
                    break;
                }
            }
            if (empty($fks)) {
                foreach ($link as $relatedAttribute => $modelAttribute) {
                    if (isset($data[$modelAttribute])) {
                        $fks[$modelAttribute] = $data[$modelAttribute];
                    }
                }
            }
        } else {
            $fks = $data;
        }
        return $fks;
    }
518242
protected function cacheManyRelationResults(string $parentKey, string $relation, $results, Relationship $relationship)
    {
        $this->cache[$parentKey][$relation] = [];

        foreach ($results as $result) {
            $cachedRelationship = $this->getCachedRelationship($relation, $result, $relationship);

            $relatedHash = $cachedRelationship->getHash();

            $this->cache[$parentKey][$relation][$relatedHash] = $cachedRelationship;
        }
    }
390427
public static function findRelation($row, $relation): array
    {
        $model = $row->getTable()->getModel();

        /** @var \Bluz\Db\Table $relationTable */
        $relationTable = self::getModelClass($relation);
        $relationTable::getInstance();

        if (!$relations = self::getRelations($model, $relation)) {
            throw new RelationNotFoundException(
                "Relations between model `$model` and `$relation` is not defined"
            );
        }

        // check many-to-many relations
        if (\count($relations) === 1) {
            $relations = self::getRelations($model, current($relations));
        }

        $field = $relations[$model];
        $key = $row->{$field};

        return self::findRelations($model, $relation, [$key]);
    }
272281
protected function matchToMorphParents($type, EntityCollection $results, array $parents)
    {
        $mapper = $this->relatedMapper->getManager()->mapper($type);
        $keyName = $mapper->getEntityMap()->getKeyName();

        $keys = array_map(function ($parent) use ($keyName) {
            return $parent[$keyName];
        }, $parents);

        $parents = array_combine($keys, $parents);

        foreach ($results as $result) {
            $key = $result[$keyName];

            if (isset($this->dictionary[$type][$key])) {
                foreach ($this->dictionary[$type][$key] as $parent) {
                    $parents[$parent[$keyName]][$this->relation] = $result;
                }
            }
        }

        return array_values($parents);
    }