Create relationship contains a collection of resource-identifiers

@param  mixed                  $object
@param  RelationshipDefinition $definition
@param  MappingContext         $context
@return IdentifierCollectionRelationship
194592
protected function createIdentifierCollectionRelationship($object, RelationshipDefinition $definition, MappingContext $context): IdentifierCollectionRelationship
    {
        $relationship = new IdentifierCollectionRelationship();
        $collection   = $object->{$definition->getGetter()}();
        $dataLimit    = $definition->getDataLimit();

        if ($dataLimit > 0) {
            $collection = new \LimitIterator($collection, 0, $dataLimit);
        }

        $mapper = $context->getMapper();

        foreach ($collection as $relatedObject)
        {
            $resource = $mapper->toResourceIdentifier($relatedObject);

            $relationship->addIdentifier($resource);
        }

        return $relationship;
    }
701403
public function persistObject(PersistenceContext $context, ITypedObject $object) : \Dms\Core\Persistence\Db\Row
    {
        return $this->persistAllObjects($context, [0 => $object])[0];
    }
330843
private function defineRelation(callable $mapperLoader)
    {
        if (!$this->tableName || !$this->primaryKeyName || !$this->foreignKeyToParentName) {
            throw new InvalidOperationException(
                    'Must supply table name, primary key name and foreign key name for embedded collection relation'
            );
        }

        call_user_func($this->callback, $mapperLoader, $this->tableName, $this->primaryKeyName, $this->foreignKeyToParentName);
    }
1200982
public function fromArray($resourceDefinition, array $body, ContextContract $context) : ResourceContract
    {
        $resourceDefinition = ResourceDefinitionLibrary::make($resourceDefinition);
        if (!Action::isWriteContext($context->getAction())) {
            throw InvalidContextAction::expectedWriteable($context->getAction());
        }

        $resource = new RESTResource($resourceDefinition);
        $resource->setSource($body);

        $fields = $resourceDefinition->getFields();

        foreach ($fields as $field) {
            $this->currentPath->push($field);

            if ($this->isWritable($field, $context)) {
                if ($field instanceof RelationshipField) {
                    $this->relationshipFromArray($field, $body, $resource, $context);
                } else {
                    try {
                        $value = $this->propertyResolver->resolvePropertyInput(
                            $this,
                            $body,
                            $field,
                            $context
                        );

                        $resource->setProperty($field, $value, true);
                    } catch (ValueUndefined $e) {
                        // Don't worry, be happy.
                    }
                }
            }
            $this->currentPath->pop();
        }

        return $resource;
    }
1038096
public function fromInput(
        $resourceDefinition,
        ContextContract $context,
        $request = null
    ): ResourceCollection
    {
        $resourceDefinition = ResourceDefinitionLibrary::make($resourceDefinition);

        $resources = $context->getInputParser()->getResources(
            $this,
            $resourceDefinition,
            $context,
            $request
        );

        if (!$resources) {
            throw new \InvalidArgumentException("No data found in body");
        }

        return $resources;
    }
690792
private function convertToFieldDefintionObject($identifier, $fieldDefinition)
    {
        if ($fieldDefinition instanceof FieldDefinitionObject) {
            return $fieldDefinition;
        } else {
            return new FieldDefinitionObject($identifier, $this, $fieldDefinition);
        }
    }
615255
private Set<Resource> fetchRelationFromEntity(IncludeRequest request, List<Resource> sourceResources, ResourceField
			relationshipField, boolean allowLookup, boolean fetchRelatedEntity, boolean mustInclude) {
		Set<Resource> loadedResources = new HashSet<>();
		for (Resource sourceResource : sourceResources) {
			ResourceIdentifier id = sourceResource.toIdentifier();

			Object sourceEntity = request.getEntity(id);
			if (sourceEntity != null && !(sourceEntity instanceof Resource)) {

				Object relatedEntity = null;
				if (fetchRelatedEntity) {
					relatedEntity = relationshipField.getAccessor().getValue(sourceEntity);
					if (!allowLookup && Iterable.class.isAssignableFrom(relationshipField.getType()) && relatedEntity == null) {
						// note that single-valued relations are allowed to be null
						throw new InternalServerErrorException(
								id + " relationship field collection '" + relationshipField.getJsonName()
										+ "' can not be null. Either set the relationship as an empty "
										+ Iterable.class.getCanonicalName() + " or use LookupIncludeBehavior.AUTOMATICALLY_ALWAYS");
					}
				}

				// attempt to work with full relationship and fallback to relationshipId where possible
				if (relatedEntity != null) {
					List<Resource> relatedResources =
							request.setupRelation(sourceResource, relationshipField, relatedEntity);
					loadedResources.addAll(relatedResources);
				} else if (relationshipField.hasIdField()) {
					Object relatedEntityID = relationshipField.getIdAccessor().getValue(sourceEntity);
					request.setupRelationId(sourceResource, relationshipField, relatedEntityID);
					if (fetchRelatedEntity && relatedEntityID != null && !allowLookup && mustInclude) {
						throw new IllegalStateException("inconsistent relationship '" + relationshipField.getUnderlyingName()
								+ "' for " + id + ", id "
								+ "set to " + relatedEntityID + ", but related object is null and lookup disabled");
					}
				}
			}
		}
		return loadedResources;
	}
1255283
private function getRelatedResources($object, ?string $format, array $context, array $relationships): array
    {
        if (!isset($context['api_included'])) {
            return [];
        }

        $included = [];
        foreach ($relationships as $relationshipDataArray) {
            if (!\in_array($relationshipDataArray['name'], $context['api_included'], true)) {
                continue;
            }

            $relationshipName = $relationshipDataArray['name'];
            $relationContext = $context;
            $attributeValue = $this->getAttributeValue($object, $relationshipName, $format, $relationContext);

            if (!$attributeValue) {
                continue;
            }

            // Many to one relationship
            if ('one' === $relationshipDataArray['cardinality']) {
                $included[] = $attributeValue['data'];

                continue;
            }
            // Many to many relationship
            foreach ($attributeValue as $attributeValueElement) {
                if (isset($attributeValueElement['data'])) {
                    $included[] = $attributeValueElement['data'];
                }
            }
        }

        return $included;
    }
1236112
public function getIdentifiers(
        ResourceTransformer $resourceTransformer,
        ResourceDefinition $resourceDefinition,
        Context $context,
        $request = null
    ) {
        $this->checkExists();

        /** @var InputParser $inputParser */
        foreach ($this as $inputParser) {
            $inputParser = InputParserLibrary::make($inputParser);
            $content = $inputParser->getIdentifiers($resourceTransformer, $resourceDefinition, $context, $request);

            if ($content) {
                return $content;
            }
        }

        return null;
    }
1271074
private function addServiceInlinedDefinitionsSetup($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, $isSimpleInstance)
    {
        $this->referenceVariables[$id] = new Variable('instance');

        $code = '';
        foreach ($inlinedDefinitions as $def) {
            if ($definition === $def || !$this->hasReference($id, array($def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()), true)) {
                continue;
            }

            // if the instance is simple, the return statement has already been generated
            // so, the only possible way to get there is because of a circular reference
            if ($isSimpleInstance) {
                throw new ServiceCircularReferenceException($id, array($id));
            }

            $name = (string) $this->definitionVariables[$def];
            $code .= $this->addServiceProperties($def, $name);
            $code .= $this->addServiceMethodCalls($def, $name);
            $code .= $this->addServiceConfigurator($def, $name);
        }

        if ('' !== $code && ($definition->getProperties() || $definition->getMethodCalls() || $definition->getConfigurator())) {
            $code .= "\n";
        }

        return $code;
    }
1342493
public function toResourceIdentifier($object): ResourceIdentifierObject
    {
        $context = $this->createContext(get_class($object));

        $id   = $this->identifierHandler->getIdentifier($object, $context);
        $type = $this->resolveType($object, $context);

        return new ResourceIdentifierObject($id, $type);
    }
615483
protected function persistObject($object, $parentIdentifier)
    {
        if (isset($this->visitedDuringPersistence[$object])) {
            return $this->visitedDuringPersistence[$object];
        }

        $identifier = $this->persistenceSession->getIdentifierByObject($object);
        $this->visitedDuringPersistence[$object] = $identifier;

        $objectData = [];
        $objectState = $this->storeObject($object, $identifier, $parentIdentifier, $objectData);

        if ($this->reflectionService->getClassSchema($object)->getModelType() === ClassSchema::MODELTYPE_ENTITY) {
            $this->persistenceSession->registerReconstitutedEntity($object, $objectData);
        }
        $this->emitPersistedObject($object, $objectState);

        return $identifier;
    }
706343
public function delete(EntityDefinition $definition, array $ids, WriteContext $writeContext): DeleteResult
    {
        $this->validateWriteInput($ids);

        $commandQueue = new WriteCommandQueue();

        $fields = $definition->getPrimaryKeys();

        $resolved = [];
        foreach ($ids as $raw) {
            $mapped = [];

            /** @var Field $field */
            foreach ($fields as $field) {
                if (!($field instanceof StorageAware)) {
                    continue;
                }

                if (array_key_exists($field->getPropertyName(), $raw)) {
                    $mapped[$field->getStorageName()] = $raw[$field->getPropertyName()];
                    continue;
                }

                if ($field instanceof ReferenceVersionField) {
                    $mapped[$field->getStorageName()] = $writeContext->getContext()->getVersionId();
                    continue;
                }

                if ($field instanceof VersionField) {
                    $mapped[$field->getStorageName()] = $writeContext->getContext()->getVersionId();
                    continue;
                }

                $fieldKeys = $fields
                    ->filter(function (Field $field) {
                        return !$field instanceof VersionField && !$field instanceof ReferenceVersionField;
                    })
                    ->map(function (Field $field) {
                        return $field->getPropertyName();
                    });

                throw new IncompletePrimaryKeyException($fieldKeys);
            }

            $resolved[] = $mapped;
        }

        if (!$definition instanceof MappingEntityDefinition) {
            $restrictions = $this->foreignKeyResolver->getAffectedDeleteRestrictions($definition, $resolved, $writeContext->getContext());

            if (!empty($restrictions)) {
                $restrictions = array_map(function ($restriction) {
                    return new RestrictDeleteViolation($restriction['pk'], $restriction['restrictions']);
                }, $restrictions);

                throw new RestrictDeleteViolationException($definition, $restrictions, $this->registry);
            }
        }

        $cascades = [];
        if (!$definition instanceof MappingEntityDefinition) {
            $cascadeDeletes = $this->foreignKeyResolver->getAffectedDeletes($definition, $resolved, $writeContext->getContext());

            $cascadeDeletes = array_column($cascadeDeletes, 'restrictions');
            foreach ($cascadeDeletes as $cascadeDelete) {
                $cascades = array_merge_recursive($cascades, $cascadeDelete);
            }

            foreach ($cascades as $affectedDefinitionClass => &$cascade) {
                $affectedDefinition = $this->registry->get($affectedDefinitionClass);

                $cascade = array_map(function ($key) use ($affectedDefinition) {
                    $payload = $key;

                    if (!\is_array($key)) {
                        $payload = ['id' => $key];
                    }

                    return new EntityWriteResult($key, $payload, $affectedDefinition, null);
                }, $cascade);
            }
        }

        $skipped = [];
        foreach ($resolved as $mapped) {
            $mappedBytes = array_map(function ($id) {
                return Uuid::fromHexToBytes($id);
            }, $mapped);

            $existence = $this->gateway->getExistence($definition, $mappedBytes, [], $commandQueue);

            if (!$existence->exists()) {
                $skipped[$definition->getClass()][] = new EntityWriteResult($mapped, $mapped, $definition, $existence);
                continue;
            }

            $commandQueue->add(
                $definition,
                new DeleteCommand(
                    $definition,
                    $mappedBytes,
                    $existence
                )
            );
        }

        $writeContext->setLanguages($this->languageLoader->loadLanguages());
        $identifiers = $this->getWriteResults($commandQueue);
        $this->gateway->execute($commandQueue->getCommandsInOrder(), $writeContext);

        return new DeleteResult(
            array_merge_recursive($identifiers, $cascades),
            $skipped
        );
    }
512269
public function load(LoadingContext $context, ParentChildMap $map)
    {
        $filteredParentMap = new ParentChildMap();
        $parentItemMap     = new \SplObjectStorage();
        $relatedEntityMap  = $context->getIdentityMap($this->mapper->getObjectType());

        foreach ($map->getItems() as $item) {
            $relatedId = $item->getParent()->getColumn($this->foreignKeyToRelated);

            if ($relatedId === null) {
                $item->setChild(null);
            } elseif ($this->reference instanceof RelationIdentityReference) {
                $item->setChild((int)$relatedId);
            } elseif ($relatedEntityMap->has($relatedId)) {
                $item->setChild($relatedEntityMap->get($relatedId));
            } else {
                $filteredParentMap->add($item->getParent(), null);
                $parentItemMap[$item->getParent()] = $item;
            }
        }

        if ($filteredParentMap->getAllChildren()) {
            parent::load($context, $filteredParentMap);

            foreach ($filteredParentMap->getItems() as $item) {
                /** @var ParentChildItem $originalItem */
                $originalItem = $parentItemMap[$item->getParent()];
                $originalItem->setChild($item->getChild());
            }
        }
    }
1318318
public function getIdentifiers(
        ResourceTransformer $resourceTransformer,
        ResourceDefinition $resourceDefinition,
        Context $context,
        $request = null
    ) {
        if (!$this->hasApplicableContentType()) {
            return;
        }

        $identifierCollection = new IdentifierCollection();

        $post = $this->getPostFromRequest($request);

        $identifier = $this->arrayToIdentifier($resourceDefinition, $post);
        if ($identifier) {
            $identifierCollection->add($identifier);
        }

        return $identifierCollection;
    }
434209
public static function resolveConcreteType(Endpoint $endpoint, PolymorphicDefinitionInterface $definition, $object)
    {
        //if discriminator map is set is used to get the value type
        if ($map = $definition->getDiscriminatorMap()) {
            //get concrete type based on property
            if ($definition->getDiscriminatorProperty()) {
                $property = $definition->getDiscriminatorProperty();
                $accessor = new PropertyAccessor();
                $propValue = $accessor->getValue($object, $property);
                $resolvedType = $map[$propValue] ?? null;
            }

            //get concrete type based on class
            if (!$resolvedType) {
                $class = DoctrineClassUtils::getClass($object);
                $resolvedType = $map[$class] ?? null;
            }
        }

        //final solution in case of not mapping is guess type based on class
        if (!$resolvedType && $definition instanceof InterfaceDefinition) {
            foreach ($definition->getImplementors() as $implementor) {
                $implementorDef = $endpoint->getType($implementor);
                if ($implementorDef instanceof ClassAwareDefinitionInterface
                    && $implementorDef->getClass() === DoctrineClassUtils::getClass($object)) {
                    $resolvedType = $implementorDef->getName();
                }
            }
        }

        if ($endpoint->hasType($resolvedType)) {
            $resolvedTypeDefinition = $endpoint->getType($resolvedType);
            if ($resolvedTypeDefinition instanceof PolymorphicDefinitionInterface) {
                $resolvedType = self::resolveConcreteType($endpoint, $resolvedTypeDefinition, $object);
            }
        }

        return $resolvedType;
    }
661814
public function populateIdentifier(DataObject $object, $identifier)
    {
        if ($field = $this->getDefaultIdentifier()) {
            
            return $object->setField($field, $identifier);
            
        } else {
            
            if ($this->getSchema()->fieldSpec($object, 'Title')) {
                return $object->setField('Title', $this->getIdentifierAsTitle($identifier));
            }
            
            if ($this->getSchema()->fieldSpec($object, 'Name')) {
                return $object->setField('Name', $this->getIdentifierAsTitle($identifier));
            }
            
        }
        
        return $object;
    }