Cache a many relationship.

@param string           $parentKey
@param string           $relation
@param EntityCollection $results
@param Relationship     $relationship

@throws MappingException
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;
        }
    }
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]));
        }
    }
129221
public function load(LoadingContext $context, ParentChildMap $map)
    {
        if (!$map->getItems()) {
            return;
        }
        
        $select = $this->getRelationSelectFromParentRows($map, $parentIdColumnName);

        $this->loadFromSelect($context, $map, $select, $select->getTableAlias(), $parentIdColumnName);
    }
670698
public function match(array $models, Collection $results, $relation)
    {
        $foreign = $this->foreignKey;

        $owner = $this->ownerKey;

        // First we will get to build a dictionary of the child models by their primary
        // key of the relationship, then we can easily match the children back onto
        // the parents using that dictionary and the primary key of the children.
        $dictionary = [];

        foreach ($results as $result) {
            if (is_array($owner)) { //Check for multi-columns relationship
                $dictKeyValues = array_map(function ($k) use ($result) {
                    return $result->{$k};
                }, $owner);

                $dictionary[implode('-', $dictKeyValues)] = $result;
            } else {
                $dictionary[$result->getAttribute($owner)] = $result;
            }
        }

        // Once we have the dictionary constructed, we can loop through all the parents
        // and match back onto their children using these keys of the dictionary and
        // the primary key of the children to map them onto the correct instances.
        foreach ($models as $model) {
            if (is_array($foreign)) { //Check for multi-columns relationship
                $dictKeyValues = array_map(function ($k) use ($model) {
                    return $model->{$k};
                }, $foreign);

                $key = implode('-', $dictKeyValues);
            } else {
                $key = $model->{$foreign};
            }

            if (isset($dictionary[$key])) {
                $model->setRelation($relation, $dictionary[$key]);
            }
        }

        return $models;
    }
672620
public function match(array $models, Collection $results, $relation)
    {
        return $this->matchOneOrMany($models, $results, $relation, 'many');
    }
584409
public function match(array $results, $relation)
    {
        $foreign = $this->foreignKey;

        $other = $this->otherKey;

        // Execute the relationship and get related entities as an EntityCollection
        $entities = $this->getEager();

        // First we will get to build a dictionary of the child models by their primary
        // key of the relationship, then we can easily match the children back onto
        // the parents using that dictionary and the primary key of the children.
        $dictionary = [];

        // TODO ; see if otherKey is the primary key of the related entity, we can
        // simply use the EntityCollection key to match entities to results, which
        // will be much more efficient, and use this method as a fallback if the
        // otherKey is not the same as the primary Key.
        foreach ($entities as $entity) {
            $entity = $this->factory->make($entity);
            $dictionary[$entity->getEntityAttribute($other)] = $entity->getObject();
        }

        // Once we have the dictionary constructed, we can loop through all the parents
        // and match back onto their children using these keys of the dictionary and
        // the primary key of the children to map them onto the correct instances.
        return array_map(function ($result) use ($dictionary, $foreign, $relation) {
            if (array_key_exists($foreign, $result) && isset($dictionary[$result[$foreign]])) {
                $result[$relation] = $dictionary[$result[$foreign]];
            } else {
                $result[$relation] = null;
            }

            return $result;
        }, $results);
    }
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);
    }
1336911
public function match(array $models, array $results, $relation)
    {
        $dictionary = $this->buildDictionary($results);

        // Once we have an array dictionary of child objects we can easily match the
        // children back to their parent using the dictionary and the keys on the
        // the parent models. Then we will return the hydrated models back out.
        foreach ($models as $model) {
            if (isset($dictionary[$key = $model->getKey()])) {
                $model->setRelation(
                    $relation, $dictionary[$key]
                );
            } else {
                $model->setRelation($relation, []);
            }
        }

        return $models;
    }
763808
@Override
	public void cacheResult(
		List<CommerceDiscountUserSegmentRel> commerceDiscountUserSegmentRels) {
		for (CommerceDiscountUserSegmentRel commerceDiscountUserSegmentRel : commerceDiscountUserSegmentRels) {
			if (entityCache.getResult(
						CommerceDiscountUserSegmentRelModelImpl.ENTITY_CACHE_ENABLED,
						CommerceDiscountUserSegmentRelImpl.class,
						commerceDiscountUserSegmentRel.getPrimaryKey()) == null) {
				cacheResult(commerceDiscountUserSegmentRel);
			}
			else {
				commerceDiscountUserSegmentRel.resetOriginalValues();
			}
		}
	}
665736
public static function setResponseDataRelationshipSelfLinks($propertyName, array &$mappings, array &$parent)
    {
        $data = [];
        $parentType = $parent[Serializer::CLASS_IDENTIFIER_KEY];

        if (\is_scalar($parentType) && !empty($mappings[$parentType])) {
            $copy = $parent;
            RecursiveFormatterHelper::formatScalarValues($copy);
            if (!empty($copy[Serializer::CLASS_IDENTIFIER_KEY])) {
                unset($copy[Serializer::CLASS_IDENTIFIER_KEY]);
            }

            $idProperties = array_keys($copy);
            foreach ($idProperties as &$property) {
                $property = sprintf('{%s}', $property);
            }
            $idValues = array_values($copy);

            if (!empty($mappings[$parentType]) && !empty($selfLink = $mappings[$parentType]->getRelationshipSelfUrl($propertyName))) {
                $url = self::buildUrl($mappings, $idProperties, $idValues, $selfLink, $parentType);

                if ($url !== $selfLink) {
                    $data[JsonApiTransformer::SELF_LINK][JsonApiTransformer::LINKS_HREF] = $url;
                }
            }
        }

        return $data;
    }
499417
protected function insertRelated(PersistenceContext $context, ParentChildMap $map)
    {
        $primaryKey = $map->getPrimaryKeyColumn();
        /** @var Row[] $parents */
        $parents = [];
        /** @var array $children */
        $children = [];

        foreach ($map->getItems() as $key => $item) {
            $parents[$key]  = $item->getParent();
            $children[$key] = $item->getChild();
        }

        $rows = $this->reference->syncRelated($context, [$this->foreignKeyColumn], $children);

        $selfReferencingChildRows = [];

        foreach ($rows as $key => $row) {
            $parent = $parents[$key];

            if ($parent->hasColumn($primaryKey)) {
                $this->setForeignKey([$row], $this->foreignKeyToParent, $parent->getColumn($primaryKey));
            } else {
                $parent->onInsertPrimaryKey(function ($id) use ($row) {
                    $this->setForeignKey([$row], $this->foreignKeyToParent, $id);
                });

                if ($parent === $row) {
                    $selfReferencingChildRows[] = $row;
                }
            }
        }

        if ($selfReferencingChildRows) {
            // If the rows are self-referencing and need to be inserted
            // an extra step must be taken because the primary key will
            // only be known after inserting so the foreign key to itself
            // will have to be updated separately afterwards
            $context->bulkUpdate(new RowSet($this->relatedTable->withColumnsButIgnoringConstraints([
                $this->relatedPrimaryKey,
                $this->foreignKeyColumn,
            ]), $selfReferencingChildRows));
        }
    }
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);
    }
1033449
public function loadRelation(LoadingContext $context, ParentMapBase $map)
    {
        if (!$map->getAllParents()) {
            return;
        }

        $separateTableRelations = $this->memberMapping->getSeperateTableRelations();

        /** @var ISeparateTableRelation|null $firstRelation */
        $firstRelation = array_shift($separateTableRelations);

        if (!$firstRelation) {
            $this->memberMapping->getRelation()->load($context, $map);

            return;
        }

        $relationSelect = $firstRelation->getRelationSelectFromParentRows($map, $parentIdColumnName, $mapIdColumn);

        if ($mapIdColumn) {
            $map = $map->withPrimaryKeyColumn($mapIdColumn);
        }

        $tableAlias = $relationSelect->getTableAlias();

        foreach ($separateTableRelations as $relation) {
            $tableAlias = $relation->joinSelectToRelatedTable(
                $tableAlias,
                Join::INNER,
                $relationSelect
            );
        }

        $parentIdColumn = $relationSelect->getAliasColumnMap()[$parentIdColumnName];
        $relationSelect->setColumns(['__parent_id__' => $parentIdColumn]);
        $parentIdColumnName = '__parent_id__';

        $allRelations = $this->memberMapping->getRelationsToSubSelect();
        $lastRelation = end($allRelations);

        if ($lastRelation instanceof ISeparateToOneTableRelation) {
            /** @var ParentChildMap $map */
            $lastRelation->loadFromSelect($context, $map, $relationSelect, $tableAlias, $parentIdColumnName);
        } elseif ($lastRelation instanceof ISeparateToManyTableRelation) {
            /** @var ParentChildrenMap $map */
            $lastRelation->loadFromSelect($context, $map, $relationSelect, $tableAlias, $parentIdColumnName);
        } elseif ($lastRelation instanceof EmbeddedObjectRelation) {
            /** @var ParentChildMap $map */
            $this->loadEmbeddedObjectRelation($context, $map, $lastRelation, $relationSelect, $tableAlias, $parentIdColumnName);
        } else {
            throw InvalidArgumentException::format('Unknown relation type %s', get_class($lastRelation));
        }
    }
1109624
private function fillRelationshipAsCollection($data, $relationship, $key)
    {
        foreach ($relationship as $index => $relationshipData) {
            $data['data'][$index]['relationships'][$key] = $relationshipData;

            if ($this->shouldIncludeLinks()) {
                $data['data'][$index]['relationships'][$key] = array_merge([
                    'links' => [
                        'self' => "{$this->baseUrl}/{$data['data'][$index]['type']}/{$data['data'][$index]['id']}/relationships/$key",
                        'related' => "{$this->baseUrl}/{$data['data'][$index]['type']}/{$data['data'][$index]['id']}/$key",
                    ],
                ], $data['data'][$index]['relationships'][$key]);
            }
        }

        return $data;
    }
1361257
public function eagerlyResult(&$result, $relation, $subRelation, $closure)
    {
        $pk = $result->getPk();

        if (isset($result->$pk)) {
            $pk   = $result->$pk;
            $data = $this->eagerlyMorphToOne([
                [$this->morphKey, '=', $pk],
                [$this->morphType, '=', $this->type],
            ], $relation, $subRelation, $closure);

            if (isset($data[$pk])) {
                $relationModel = $data[$pk];
                $relationModel->setParent(clone $result);
                $relationModel->isUpdate(true);
            } else {
                $relationModel = null;
            }

            $result->setRelation(Db::parseName($relation), $relationModel);
        }
    }
326661
public function match(array $models, Collection $results, $relation)
    {
        return $this->matchOne($models, $results, $relation);
    }
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;
    }