@param IObjectMapping $mapping
@param Row[]          $rows
@param ITypedObject[] $objects

@return array
179002
protected function loadInstancesForSubclass(IObjectMapping $mapping, array $rows, array $objects): array
    {
        $subClass          = $mapping->getObjectType();
        $objectsOfSubClass = [];
        $rowsForSubClass   = [];

        foreach ($objects as $key => $object) {
            if ($object instanceof $subClass) {
                $objectsOfSubClass[$key] = $object;
                $rowsForSubClass[$key]   = $rows[$key];
            }
        }

        return [$objectsOfSubClass, $rowsForSubClass];
    }
72423
protected function cacheMapping($mapping)
    {
        $mapping = array_filter($mapping);
        if ($mapping && !empty($mapping)) {
            $cache = SS_Cache::factory('gridfieldimporter');
            $cache->save(serialize($mapping), $this->cacheKey());
        }
    }
880223
public static function setResponseDataAttributes(array &$mappings, array &$array)
    {
        $attributes = [];
        $type = $array[Serializer::CLASS_IDENTIFIER_KEY];
        $idProperties = RecursiveFormatterHelper::getIdProperties($mappings, $type);

        foreach ($array as $propertyName => $value) {
            $keyName = self::transformToValidMemberName(RecursiveFormatterHelper::camelCaseToUnderscore($propertyName));

            if (\in_array($propertyName, $idProperties, true)) {
                self::addIdPropertiesInAttribute($mappings, $type, $keyName, $value, $attributes);
                continue;
            }

            if (!empty($value[Serializer::CLASS_IDENTIFIER_KEY])
                && empty($mappings[$value[Serializer::CLASS_IDENTIFIER_KEY]])
            ) {
                $copy = $value;
                self::recursiveSetKeysToUnderScore($copy);
                $attributes[$keyName] = $copy;
                continue;
            }

            if (self::isScalarValue($value) && empty($mappings[$value[Serializer::SCALAR_TYPE]])) {
                $attributes[$keyName] = $value;
                continue;
            }

            if (\is_array($value) && !array_key_exists(Serializer::CLASS_IDENTIFIER_KEY, $value)) {
                if (false === self::hasClassIdentifierKey($value)) {
                    $attributes[$keyName] = $value;
                }
            }
        }

        //Guarantee it always returns the same attribute order. No matter what.
        ksort($attributes, SORT_STRING);

        return [JsonApiTransformer::ATTRIBUTES_KEY => $attributes];
    }
602632
private function loadRelations(
        LoadingContext $context,
        array $rows,
        array $objects,
        array &$objectProperties
    ) {
        $isLazyLoadingEnabled = $this->definition->isLazyLoadingEnabled();

        foreach ($this->definition->getToOneRelationMappings() as $relationMapping) {
            $relation = $relationMapping->getRelation();
            $accessor = $relationMapping->getAccessor();

            $map       = new ParentChildMap($this->primaryKeyColumnName);
            $rowKeyMap = new \SplObjectStorage();

            foreach ($rows as $key => $row) {
                $map->add($row, null);
                $rowKeyMap[$row] = $key;
            }

            $relation->load($context, $map);

            foreach ($map->getItems() as $item) {
                $objectKey = $rowKeyMap[$item->getParent()];
                $accessor->set($objects[$objectKey], $objectProperties[$objectKey], $item->getChild());
            }
        }

        foreach ($this->definition->getToManyRelationMappings() as $relationMapping) {

            $relation = $relationMapping->getRelation();
            $accessor = $relationMapping->getAccessor();

            $map       = new ParentChildrenMap($this->primaryKeyColumnName);
            $rowKeyMap = new \SplObjectStorage();

            foreach ($rows as $key => $row) {
                $map->add($row, []);
                $rowKeyMap[$row] = $key;
            }

            $hasLoaded = false;

            if (!$isLazyLoadingEnabled) {
                $relation->load($context, $map);
                $hasLoaded = true;
            }

            foreach ($map->getItems() as $item) {
                $objectKey = $rowKeyMap[$item->getParent()];
                $object    = $objects[$objectKey];

                if ($hasLoaded) {
                    $collection = $relation->buildCollection($item->getChildren());
                } else {
                    $collection = LazyCollectionFactory::from(
                        $relation->buildCollection([]),
                        function () use (&$hasLoaded, $relation, $context, $map, $item) {
                            if (!$hasLoaded) {
                                $relation->load($context, $map);
                                $hasLoaded = true;
                            }

                            return $item->getChildren();
                        }
                    );

                    $collection->appendLazyMetadata([
                        'parent'   => $object,
                        'relation' => $relation,
                    ]);
                }

                $accessor->set($object, $objectProperties[$objectKey], $collection);
            }

            unset($hasLoaded);
        }
    }
458129
public function populateManyRelationByIDs(DataObject $object, $field, $ids = [])
    {
        // Define Relation:
        
        if (!empty($ids)) {
            $this->getRelationList($object, $field)->setByIDList($ids);
        }
        
        // Answer Object:
        
        return $object;
    }
1246308
protected function mapLoadExpressionToRelations(
        IObjectMapper $mapper,
        LoadIdFromEntitySetMethodExpression $part,
        IObjectMapper &$finalMapper = null
    ) : array
    {
        /** @var EntityRelation $relationToLoadAsObject */
        $innerRelations         = $this->mapMemberExpressionsToRelations($mapper, $part->getIdMember()->getParts(), $finalMapper);
        $relationToLoadAsObject = array_pop($innerRelations);

        $relationsToAdd   = $innerRelations;
        $relationsToAdd[] = $relationToLoadAsObject->withObjectReference();

        return $relationsToAdd;
    }
713444
public function persistAllObjects(PersistenceContext $context, array $objects) : array
    {
        $rows = [];

        foreach ($objects as $key => $object) {
            $rows[$key] = new Row($this->table);
        }

        $this->persistAll($context, $objects, $rows);

        return $rows;
    }
325417
public function extract($object, array $map = null): array
    {
        $result = [];

        $className = \get_class($object);
        $reflection = $this->getReflection($className);

        if (!\is_array($map) || !$map) {
            $propertyList = $this->getReflectionPropertyList($className);
            $map = \array_combine($propertyList, $propertyList);
        }
        foreach ($map as $fieldName => $propertyName) {
            if ($reflection->hasProperty($propertyName)) {
                $property = $this->getProperty($reflection, $propertyName);
                $result[$fieldName] = $property->getValue($object);
            }
        }

        return $result;
    }
551446
protected function createObjects($rows)
    {
        $models = [];

        foreach ($rows as $key => $row) {
            $models[$key] = $this->createObject($row);
        }

        return $models;
    }
923768
public static function setResponseDataTypeAndId(array &$mappings, array &$value)
    {
        if (empty($type = $value[Serializer::CLASS_IDENTIFIER_KEY]) || (empty($mappings[$type]))) {
            return [];
        }

        if (!is_scalar($type)) {
            return self::setResponseDataTypeAndId($mappings, $type);
        }

        $finalType = ($mappings[$type]->getClassAlias()) ? $mappings[$type]->getClassAlias() : $type;
        $ids = self::getIdValues($mappings, $value, $type);

        return [
            JsonApiTransformer::TYPE_KEY => RecursiveFormatterHelper::namespaceAsArrayKey($finalType),
            JsonApiTransformer::ID_KEY => \implode(JsonApiTransformer::ID_SEPARATOR, $ids),
        ];
    }
796142
public function hydrate(array $data, array $nestedObjects = [], array $method_mapper = [])
    {
        foreach ($data as $key => $value) {
            if (!$value) {
                continue;
            }

            if (!\in_array($key, $nestedObjects)) {
                // get setter method for each key in data
                $setter = 'set' . Inflector::classify($key);
                if (method_exists($this, $setter)) {
                    $this->$setter($value);
                } else {
                    // check if setter method exists that doesn't match inflected filter format
                    if (\in_array($setter, array_keys($method_mapper))) {
                        $this->{$method_mapper[$setter]}($value);
                    } else {
                        // value is not set - Entities should be extended if needed
                    }
                }
            } else {
                // try to hydrate the nested objects
                foreach ($nestedObjects as $currentNestedObject) {
                    // if empty then ignore
                    if (!empty($data[$currentNestedObject])) {
                        // if is not array then throw exception
                        if (\is_array($data[$currentNestedObject])) {
                            // rename for clarity
                            $nestedObject = $data[$currentNestedObject];
                            $NestedObjectCollection = [];
                            foreach ($nestedObject as $nestedObjectArguments) {
                                $singluarizedName = Inflector::singularize($currentNestedObject);
                                $className = Inflector::classify($singluarizedName);
                                $classNameWithFQDN = str_replace('Library', 'Model', __NAMESPACE__) . '\\' . $className;
                                $reflection = new \ReflectionClass($classNameWithFQDN);
                                $nestedObjectClass = $reflection->newInstanceArgs([$nestedObjectArguments]);
                                $NestedObjectCollection[] = $nestedObjectClass;
                            }
                            $setter = 'set' . ucwords($currentNestedObject);
                            $this->$setter($NestedObjectCollection);
                        } else {
                            throw new InvalidParamException(sprintf('%s must be an array', $currentNestedObject));
                        }
                    }
                }
            }
        }
    }
1311004
private function findSubclassMappings(IObjectMapper $mapper, NestedMember $member) : array
    {
        /** @var ObjectType $type */
        $type  = $member->getParts()[0]->getSourceType();
        $class = $type->getClass();

        $subclassMappings = [];

        $this->walkSubclassMappings($subclassMappings, $mapper->getMapping(), $class);

        return $subclassMappings;
    }
373805
public function objectFromIndex(IObjectSetWithIdentityByIndex $objects) : ObjectFieldBuilder
    {
        return new ObjectFieldBuilder(
            $this->type(new ObjectIdType(new ObjectIndexOptions($objects), $loadAsObjects = true))
        );
    }
559405
private static function parseMapping($mapping, &$i = 0, $references = [])
    {
        $output = [];
        $len = \strlen($mapping);
        ++$i;

        // {foo: bar, bar:foo, ...}
        while ($i < $len) {
            switch ($mapping[$i]) {
                case ' ':
                case ',':
                    ++$i;
                    continue 2;
                case '}':
                    return (object) $output;
            }

            // key
            $offsetBeforeKeyParsing = $i;
            $isKeyQuoted = in_array($mapping[$i], ['"', "'"], true);
            $key = self::parseScalar($mapping, [':', ' '], $i, false, []);

            if ($offsetBeforeKeyParsing === $i) {
                throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
            }

            if (false === $i = \strpos($mapping, ':', $i)) {
                break;
            }

            if (!$isKeyQuoted) {
                $evaluatedKey = self::evaluateScalar($key, $references);

                if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
                    throw new ParseException('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead.', self::$parsedLineNumber + 1, $mapping);
                }
            }

            if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}'], true))) {
                throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
            }

            if ('<<' === $key) {
                $allowOverwrite = true;
            }

            while ($i < $len) {
                if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
                    ++$i;

                    continue;
                }

                switch ($mapping[$i]) {
                    case '[':
                        // nested sequence
                        $value = self::parseSequence($mapping, $i, $references);
                        // Spec: Keys MUST be unique; first one wins.
                        // Parser cannot abort this mapping earlier, since lines
                        // are processed sequentially.
                        // But overwriting is allowed when a merge node is used in current block.
                        if ('<<' === $key) {
                            foreach ($value as $parsedValue) {
                                $output += $parsedValue;
                            }
                        } elseif ($allowOverwrite || !isset($output[$key])) {
                            $output[$key] = $value;
                        } elseif (isset($output[$key])) {
                            throw new ParseException(\sprintf('Duplicate key "%s" detected.',
                                $key), self::$parsedLineNumber + 1, $mapping);
                        }
                        break;
                    case '{':
                        // nested mapping
                        $value = self::parseMapping($mapping, $i, $references);
                        // Spec: Keys MUST be unique; first one wins.
                        // Parser cannot abort this mapping earlier, since lines
                        // are processed sequentially.
                        if ('<<' === $key) {
                            $output += $value;
                        } elseif ($allowOverwrite || !isset($output[$key])) {
                    		$output[$key] = $value;
                        } elseif (isset($output[$key])) {
                            throw new ParseException(\sprintf('Duplicate key "%s" detected.',
                                $key), self::$parsedLineNumber + 1, $mapping);
                        }
                        break;
                    default:
                        $value = self::parseScalar($mapping, [',', '}'], $i, true, $references);
                        // Spec: Keys MUST be unique; first one wins.
                        // Parser cannot abort this mapping earlier, since lines
                        // are processed sequentially.
                        // But overwriting is allowed when a merge node is used in current block.
                        if ('<<' === $key) {
                            $output += $value;
                        } elseif ($allowOverwrite || !isset($output[$key])) {
                            $output[$key] = $value;
                        } elseif (isset($output[$key])) {
                            throw new ParseException(\sprintf('Duplicate key "%s" detected.',
                                $key), self::$parsedLineNumber + 1, $mapping);
                        }
                        --$i;
                }
                ++$i;

                continue 2;
            }
        }

        throw new ParseException(\sprintf('Malformed inline YAML string: %s.', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename);
    }
1155647
public function from(IObjectMapper $mapper)
    {
        $this->mapper     = $mapper;
        $this->definition = $mapper->getDefinition();
        $this->relations  = $this->definition->getPropertyRelationMap();

        if ($mapper instanceof IEntityMapper) {
            foreach ($mapper->getPrimaryTable()->getColumns() as $column) {
                $this->readDefinition->addColumn($column);
            }
        }

        $this->validProperties = $this->definition->getPropertyColumnMap() + $this->relations;
    }
768823
public function mapEmbedded(array $mapping)
    {
        $this->assertFieldNotMapped($mapping['fieldName']);

        $this->embeddedClasses[$mapping['fieldName']] = array(
            'class' => $this->fullyQualifiedClassName($mapping['class']),
            'columnPrefix' => $mapping['columnPrefix'],
            'declaredField' => isset($mapping['declaredField']) ? $mapping['declaredField'] : null,
            'originalField' => isset($mapping['originalField']) ? $mapping['originalField'] : null,
        );
    }
38667
public static function addRowsToMap($rows)
    {
        $firstRow = reset($rows);
        $idAttribute = static::getIdAttribute();
        if ($firstRow instanceof ActiveRecord) {
            foreach ($rows as $row) {
                self::$identityMap[$row[$idAttribute]] = $row->toArray();
                foreach (static::getUniqueAttributes() as $uniqueAttribute) {
                    self::$uniqueAttributeToId[$uniqueAttribute][$row[$uniqueAttribute]] = $row[$idAttribute];
                }
            }
        } else {
            foreach ($rows as $row) {
                self::$identityMap[$row[$idAttribute]] = $row;
                foreach (static::getUniqueAttributes() as $uniqueAttribute) {
                    self::$uniqueAttributeToId[$uniqueAttribute][$row[$uniqueAttribute]] = $row[$idAttribute];
                }
            }
        }
        $maxSize = self::getIdentityMapMaxSize();
        if ($maxSize !== -1) {
            $count = count(self::$identityMap);
            if ($count > $maxSize) {
                self::$identityMap = array_slice(
                    self::$identityMap,
                    $count - $maxSize,
                    $maxSize
                );
            }
        }
    }