Generate pivot table for a morphToMany relation.

@param string $name
@param \ProAI\Datamapper\Annotations\Annotation $annotation
@param \ProAI\Datamapper\Metadata\Definitions\Class $entityMetadata
@return \ProAI\Datamapper\Metadata\Definitions\Table
329458
protected function generateMorphToManyPivotTable($name, Annotation $annotation, EntityDefinition &$entityMetadata)
    {
        $morphName = $annotation->morphName;

        $tableName = ($annotation->pivotTable)
            ? $annotation->pivotTable
            : $this->generatePivotTablename($entityMetadata['class'], $annotation->relatedEntity, $annotation->inverse, $morphName);

        if ($annotation->inverse) {
            $pivotKey = $annotation->localPivotKey ?: $this->generateKey($entityMetadata['class']);
        } else {
            $pivotKey = $annotation->relatedPivotKey ?: $this->generateKey($annotation->relatedEntity);
        }

        $morphId = (! empty($annotation->localKey))
            ? $annotation->localKey
            : $morphName.'_id';

        $morphType = $morphName.'_type';

        return new TableDefinition([
            'name' => $tableName,
            'columns' => [
                $this->getModifiedPrimaryKeyColumn($entityMetadata['table'], [
                    'name' => $pivotKey,
                    'options' => [
                        'autoIncrement' => false
                    ]
                ]),
                $this->getModifiedPrimaryKeyColumn($entityMetadata['table'], [
                    'name' => $morphId,
                    'options' => [
                        'autoIncrement' => false
                    ]
                ]),
                new ColumnDefinition([
                    'name' => $morphType,
                    'type' => 'string',
                    'nullable' => false,
                    'default' => false,
                    'primary' => true,
                    'unique' => false,
                    'index' => false,
                    'options' => []
                ]),
            ]
        ]);
    }
365557
public static function createEmbedMany(string $name): NormalizationFieldMappingBuilderInterface
    {
        $self = new self($name);
        $self->fieldNormalizer = new EmbedManyFieldNormalizer(new PropertyAccessor($name));

        return $self;
    }
1193389
public function createCollectionManyHasOne(PropertyMetadata $metadata): ICollection
	{
		return $this->findAll()->setRelationshipMapper(
			$this->getRelationshipMapper(Relationship::MANY_HAS_ONE, $metadata)
		);
	}
671426
protected function generateMorphToColumns($name, Annotation $annotation, EntityDefinition &$entityMetadata)
    {
        $morphName = (! empty($annotation->morphName))
            ? $annotation->morphName
            : $name;

        $morphId = (! empty($annotation->morphId))
            ? $annotation->morphId
            : $morphName.'_id';

        $morphType = (! empty($annotation->morphType))
            ? $annotation->morphType
            : $morphName.'_type';

        $entityMetadata['table']['columns'][] = $this->getModifiedPrimaryKeyColumn($entityMetadata['table'], [
            'name' => $morphId,
            'primary' => false,
            'options' => [
                'autoIncrement' => false
            ]
        ]);

        $entityMetadata['table']['columns'][] = new ColumnDefinition([
            'name' => $morphType,
            'type' => 'string',
            'nullable' => false,
            'default' => false,
            'primary' => false,
            'unique' => false,
            'index' => false,
            'options' => []
        ]);
    }
507414
private function convertReflectionPropertyToFieldMetadata(
        ReflectionProperty $reflProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $metadata
    ) : Mapping\FieldMetadata {
        $className   = $metadata->getClassName();
        $fieldName   = $reflProperty->getName();
        $isVersioned = isset($propertyAnnotations[Annotation\Version::class]);
        $columnAnnot = $propertyAnnotations[Annotation\Column::class];

        if ($columnAnnot->type === null) {
            throw Mapping\MappingException::propertyTypeIsRequired($className, $fieldName);
        }

        $fieldMetadata = $this->convertColumnAnnotationToFieldMetadata($columnAnnot, $fieldName, $isVersioned);

        // Check for Id
        if (isset($propertyAnnotations[Annotation\Id::class])) {
            $fieldMetadata->setPrimaryKey(true);
        }

        // Check for GeneratedValue strategy
        if (isset($propertyAnnotations[Annotation\GeneratedValue::class])) {
            $generatedValueAnnot = $propertyAnnotations[Annotation\GeneratedValue::class];
            $strategy            = strtoupper($generatedValueAnnot->strategy);
            $idGeneratorType     = constant(sprintf('%s::%s', Mapping\GeneratorType::class, $strategy));

            if ($idGeneratorType !== Mapping\GeneratorType::NONE) {
                $idGeneratorDefinition = [];

                // Check for CustomGenerator/SequenceGenerator/TableGenerator definition
                switch (true) {
                    case isset($propertyAnnotations[Annotation\SequenceGenerator::class]):
                        $seqGeneratorAnnot = $propertyAnnotations[Annotation\SequenceGenerator::class];

                        $idGeneratorDefinition = [
                            'sequenceName' => $seqGeneratorAnnot->sequenceName,
                            'allocationSize' => $seqGeneratorAnnot->allocationSize,
                        ];

                        break;

                    case isset($propertyAnnotations[Annotation\CustomIdGenerator::class]):
                        $customGeneratorAnnot = $propertyAnnotations[Annotation\CustomIdGenerator::class];

                        $idGeneratorDefinition = [
                            'class' => $customGeneratorAnnot->class,
                            'arguments' => $customGeneratorAnnot->arguments,
                        ];

                        break;

                    /** @todo If it is not supported, why does this exist? */
                    case isset($propertyAnnotations['Doctrine\ORM\Mapping\TableGenerator']):
                        throw Mapping\MappingException::tableIdGeneratorNotImplemented($className);
                }

                $fieldMetadata->setValueGenerator(new Mapping\ValueGeneratorMetadata($idGeneratorType, $idGeneratorDefinition));
            }
        }

        return $fieldMetadata;
    }
570115
protected function generateEntityDocBlock(ClassMetadataInfo $metadata)
    {
        $lines = array();
        $lines[] = '/**';
        $lines[] = ' * ' . $this->getClassName($metadata);

        if ($this->generateAnnotations) {
            $lines[] = ' *';

            $methods = array(
                'generateTableAnnotation',
                'generateInheritanceAnnotation',
                'generateDiscriminatorColumnAnnotation',
                'generateDiscriminatorMapAnnotation',
                'generateEntityAnnotation',
            );

            foreach ($methods as $method) {
                if ($code = $this->$method($metadata)) {
                    $lines[] = ' * ' . $code;
                }
            }

            if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
                $lines[] = ' * @' . $this->annotationsPrefix . 'HasLifecycleCallbacks';
            }
        }

        $lines[] = ' */';

        return implode("\n", $lines);
    }
882918
private function convertJoinTableAnnotationToJoinTableMetadata(
        Annotation\JoinTable $joinTableAnnot
    ) : Mapping\JoinTableMetadata {
        $joinTable = new Mapping\JoinTableMetadata();

        if (! empty($joinTableAnnot->name)) {
            $joinTable->setName($joinTableAnnot->name);
        }

        if (! empty($joinTableAnnot->schema)) {
            $joinTable->setSchema($joinTableAnnot->schema);
        }

        foreach ($joinTableAnnot->joinColumns as $joinColumnAnnot) {
            $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata($joinColumnAnnot);

            $joinTable->addJoinColumn($joinColumn);
        }

        foreach ($joinTableAnnot->inverseJoinColumns as $joinColumnAnnot) {
            $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata($joinColumnAnnot);

            $joinTable->addInverseJoinColumn($joinColumn);
        }

        return $joinTable;
    }
1322238
private function convertClassAnnotationsToClassMetadata(
        array $classAnnotations,
        ReflectionClass $reflectionClass,
        Mapping\ClassMetadata $metadata,
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
    ) : Mapping\ClassMetadata {
        switch (true) {
            case isset($classAnnotations[Annotation\Entity::class]):
                return $this->convertClassAnnotationsToEntityClassMetadata(
                    $classAnnotations,
                    $reflectionClass,
                    $metadata,
                    $metadataBuildingContext
                );

                break;

            case isset($classAnnotations[Annotation\MappedSuperclass::class]):
                return $this->convertClassAnnotationsToMappedSuperClassMetadata(
                    $classAnnotations,
                    $reflectionClass,
                    $metadata
                );
            case isset($classAnnotations[Annotation\Embeddable::class]):
                return $this->convertClassAnnotationsToEmbeddableClassMetadata(
                    $classAnnotations,
                    $reflectionClass,
                    $metadata
                );
            default:
                throw Mapping\MappingException::classIsNotAValidEntityOrMappedSuperClass($reflectionClass->getName());
        }
    }
862028
private function convertClassAnnotationsToEntityClassMetadata(
        array $classAnnotations,
        ReflectionClass $reflectionClass,
        Mapping\ClassMetadata $parent
    ) {
        /** @var Annotation\Entity $entityAnnot */
        $entityAnnot   = $classAnnotations[Annotation\Entity::class];
        $classMetadata = new Mapping\ClassMetadata($reflectionClass->getName(), $parent);

        if ($entityAnnot->repositoryClass !== null) {
            $classMetadata->setCustomRepositoryClassName($entityAnnot->repositoryClass);
        }

        if ($entityAnnot->readOnly) {
            $classMetadata->asReadOnly();
        }

        // Evaluate @Table annotation
        if (isset($classAnnotations[Annotation\Table::class])) {
            /** @var Annotation\Table $tableAnnot */
            $tableAnnot = $classAnnotations[Annotation\Table::class];
            $table      = $this->convertTableAnnotationToTableMetadata($tableAnnot);

            $classMetadata->setTable($table);
        }

        // Evaluate @ChangeTrackingPolicy annotation
        if (isset($classAnnotations[Annotation\ChangeTrackingPolicy::class])) {
            /** @var Annotation\ChangeTrackingPolicy $changeTrackingAnnot */
            $changeTrackingAnnot = $classAnnotations[Annotation\ChangeTrackingPolicy::class];

            $classMetadata->setChangeTrackingPolicy(
                constant(sprintf('%s::%s', Mapping\ChangeTrackingPolicy::class, $changeTrackingAnnot->value))
            );
        }

        // Evaluate @EntityListeners annotation
        if (isset($classAnnotations[Annotation\EntityListeners::class])) {
            /** @var Annotation\EntityListeners $entityListenersAnnot */
            $entityListenersAnnot = $classAnnotations[Annotation\EntityListeners::class];

            foreach ($entityListenersAnnot->value as $listenerClassName) {
                if (! class_exists($listenerClassName)) {
                    throw Mapping\MappingException::entityListenerClassNotFound(
                        $listenerClassName,
                        $reflectionClass->getName()
                    );
                }

                $listenerClass = new ReflectionClass($listenerClassName);

                /** @var ReflectionMethod $method */
                foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
                    foreach ($this->getMethodCallbacks($method) as $callback) {
                        $classMetadata->addEntityListener($callback, $listenerClassName, $method->getName());
                    }
                }
            }
        }

        // Evaluate @HasLifecycleCallbacks annotation
        if (isset($classAnnotations[Annotation\HasLifecycleCallbacks::class])) {
            /** @var ReflectionMethod $method */
            foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
                foreach ($this->getMethodCallbacks($method) as $callback) {
                    $classMetadata->addLifecycleCallback($method->getName(), $callback);
                }
            }
        }

        // Evaluate @InheritanceType annotation
        if (isset($classAnnotations[Annotation\InheritanceType::class])) {
            /** @var Annotation\InheritanceType $inheritanceTypeAnnot */
            $inheritanceTypeAnnot = $classAnnotations[Annotation\InheritanceType::class];

            $classMetadata->setInheritanceType(
                constant(sprintf('%s::%s', Mapping\InheritanceType::class, $inheritanceTypeAnnot->value))
            );

            if ($classMetadata->inheritanceType !== Mapping\InheritanceType::NONE) {
                $discriminatorColumn = new Mapping\DiscriminatorColumnMetadata();

                // Evaluate @DiscriminatorColumn annotation
                if (isset($classAnnotations[Annotation\DiscriminatorColumn::class])) {
                    /** @var Annotation\DiscriminatorColumn $discriminatorColumnAnnot */
                    $discriminatorColumnAnnot = $classAnnotations[Annotation\DiscriminatorColumn::class];

                    $discriminatorColumn->setColumnName($discriminatorColumnAnnot->name);

                    if (! empty($discriminatorColumnAnnot->columnDefinition)) {
                        $discriminatorColumn->setColumnDefinition($discriminatorColumnAnnot->columnDefinition);
                    }

                    if (! empty($discriminatorColumnAnnot->type)) {
                        $discriminatorColumn->setType(Type::getType($discriminatorColumnAnnot->type));
                    }

                    if (! empty($discriminatorColumnAnnot->length)) {
                        $discriminatorColumn->setLength($discriminatorColumnAnnot->length);
                    }
                }

                if (empty($discriminatorColumn->getColumnName())) {
                    throw Mapping\MappingException::nameIsMandatoryForDiscriminatorColumns($reflectionClass->getName());
                }

                $classMetadata->setDiscriminatorColumn($discriminatorColumn);

                // Evaluate @DiscriminatorMap annotation
                if (isset($classAnnotations[Annotation\DiscriminatorMap::class])) {
                    /** @var Annotation\DiscriminatorMap $discriminatorMapAnnotation */
                    $discriminatorMapAnnotation = $classAnnotations[Annotation\DiscriminatorMap::class];
                    $discriminatorMap           = $discriminatorMapAnnotation->value;

                    $classMetadata->setDiscriminatorMap($discriminatorMap);
                }
            }
        }

        return $classMetadata;
    }
1105557
protected function updateRelation($eloquentModel, $name, $relationMapping, $action)
    {
        // set foreign key for belongsTo/morphTo relation
        if ($relationMapping['type'] == 'belongsTo' || $relationMapping['type'] == 'morphTo') {
            $this->updateBelongsToRelation($eloquentModel, $name, $action);
        }

        // set foreign keys for belongsToMany/morphToMany relation
        if (($relationMapping['type'] == 'belongsToMany' || $relationMapping['type'] == 'morphToMany') && ! $relationMapping['inverse']) {
            $this->updateBelongsToManyRelation($eloquentModel, $name, $action);
        }
    }
63967
protected function _createAnnotation($name, $parsedData)
    {
        $class = static::$_classMap['default'];
        if (isset(static::$_classMap[$name])) {
            $class = static::$_classMap[$name];
        }

        $classReflection = new ReflectionClass($class);
        return $classReflection->newInstanceArgs([$name, $parsedData]);
    }
953212
protected function createRelationship(RelationshipAnnotation $annotation, \ReflectionProperty $property): Relationship
    {
        $name = ($annotation->name === null)
            ? $property->getName()
            : $annotation->name;

        $type = $this->resolveType($annotation);

        $getter = ($annotation->getter === null)
            ? $this->resolveGetter($property)
            : $annotation->getter;

        $relationship = new Relationship($name, $type, $getter);
        $relationship->setPropertyName($property->getName());

        $this->handleLinks($annotation, $relationship);
        $this->handleDataControl($annotation, $relationship);

        return $relationship;
    }
1358244
private function convertReflectionPropertyToOneToManyAssociationMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $metadata,
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
    ) : Mapping\OneToManyAssociationMetadata {
        $className      = $metadata->getClassName();
        $fieldName      = $reflectionProperty->getName();
        $oneToManyAnnot = $propertyAnnotations[Annotation\OneToMany::class];
        $assocMetadata  = new Mapping\OneToManyAssociationMetadata($fieldName);
        $targetEntity   = $oneToManyAnnot->targetEntity;

        $assocMetadata->setTargetEntity($targetEntity);
        $assocMetadata->setCascade($this->getCascade($className, $fieldName, $oneToManyAnnot->cascade));
        $assocMetadata->setOrphanRemoval($oneToManyAnnot->orphanRemoval);
        $assocMetadata->setFetchMode($this->getFetchMode($className, $oneToManyAnnot->fetch));

        if (! empty($oneToManyAnnot->mappedBy)) {
            $assocMetadata->setMappedBy($oneToManyAnnot->mappedBy);
        }

        if (! empty($oneToManyAnnot->indexBy)) {
            $assocMetadata->setIndexedBy($oneToManyAnnot->indexBy);
        }

        // Check for OrderBy
        if (isset($propertyAnnotations[Annotation\OrderBy::class])) {
            $orderByAnnot = $propertyAnnotations[Annotation\OrderBy::class];

            $assocMetadata->setOrderBy($orderByAnnot->value);
        }

        // Check for Id
        if (isset($propertyAnnotations[Annotation\Id::class])) {
            throw Mapping\MappingException::illegalToManyIdentifierAssociation($className, $fieldName);
        }

        $this->attachAssociationPropertyCache($propertyAnnotations, $reflectionProperty, $assocMetadata, $metadata);

        return $assocMetadata;
    }
70141
public function buildInput(ApiDoc $annotation, $data = null)
    {
        $annotationReflection = new \ReflectionClass('Nelmio\ApiDocBundle\Annotation\ApiDoc');
        $inputReflection = $annotationReflection->getProperty('input');
        $inputReflection->setAccessible(true);

        if (!(isset($data['input']) || $data['input'] === null) || empty($data['input'])) {
            if ($annotation->toArray()['method'] === 'POST' || $annotation->toArray()['method'] === 'PUT') {
                $actionName = $annotation->getRoute()->getDefault('_controller');
                $controllerClass = substr($actionName, 0, strpos($actionName, '::'));
                $reflectionClass = new \ReflectionClass(substr($controllerClass, strpos($controllerClass, ':')));
                $class = str_replace('Controller', '', $reflectionClass->getShortName());
                $inputType = 'Kreta\\Component\\' . $class . '\\Form\\Type\\' . $class . 'Type';
                if (class_exists($inputType)) {
                    $inputReflection->setValue($annotation, $inputType);
                }
            }
        } else {
            $inputReflection->setValue($annotation, $data['input']);
        }

        return $annotation;
    }
777281
private function hydrateDataObject(ClassMetadata $metadata, array $parentName = array())
    {
        $dataObject = new MetadataDataObjectDoctrine2(
            new MetaDataColumnCollection(),
            new MetaDataRelationCollection()
        );

        $columnDataObject = new MetaDataColumn();

        foreach ($metadata->fieldMappings as $field => $columnMetadata) {
            $column = clone $columnDataObject;
            $column->setName($field)
                   ->setType($columnMetadata['type'])
                   ->setLength(isset($columnMetadata['length']) === true ? $columnMetadata['length'] : null)
                   ->setNullable($columnMetadata['nullable'])
                   ->setPrimaryKey((in_array($field, $metadata->identifier) === true ? true : false));

            $dataObject->appendColumn($column);
        }

        $dataObject = $this->hydrateAssociation($metadata, $dataObject, $parentName);

        $dataObject->setName($metadata->name);

        return $dataObject;
    }
301388
protected function evaluatePropertyAnnotations(ORM\ClassMetadataInfo $metadata)
    {
        $className = $metadata->name;

        $class = $metadata->getReflectionClass();
        $classSchema = $this->getClassSchema($className);

        foreach ($class->getProperties() as $property) {
            if (!$classSchema->hasProperty($property->getName())
                    || $classSchema->isPropertyTransient($property->getName())
                    || $metadata->isMappedSuperclass && !$property->isPrivate()
                    || $metadata->isInheritedField($property->getName())
                    || $metadata->isInheritedAssociation($property->getName())
                    || $metadata->isInheritedEmbeddedClass($property->getName())) {
                continue;
            }

            $propertyMetaData = $classSchema->getProperty($property->getName());

            $mapping = [];
            $mapping['fieldName'] = $property->getName();
            $mapping['columnName'] = strtolower($property->getName());
            $mapping['targetEntity'] = $propertyMetaData['type'];

            $joinColumns = $this->evaluateJoinColumnAnnotations($property);

            // Field can only be annotated with one of:
            // @OneToOne, @OneToMany, @ManyToOne, @ManyToMany, @Column (optional)
            if ($oneToOneAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OneToOne::class)) {
                if ($this->reader->getPropertyAnnotation($property, ORM\Id::class) !== null) {
                    $mapping['id'] = true;
                }
                if ($oneToOneAnnotation->targetEntity !== null) {
                    $mapping['targetEntity'] = $oneToOneAnnotation->targetEntity;
                }
                if ($oneToOneAnnotation->inversedBy !== null || $oneToOneAnnotation->mappedBy === null) {
                    $mapping['joinColumns'] = $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property);
                }
                $mapping['mappedBy'] = $oneToOneAnnotation->mappedBy;
                $mapping['inversedBy'] = $oneToOneAnnotation->inversedBy;
                if ($oneToOneAnnotation->cascade !== null) {
                    $mapping['cascade'] = $oneToOneAnnotation->cascade;
                } elseif ($this->isValueObject($mapping['targetEntity'], $className)) {
                    $mapping['cascade'] = ['persist'];
                } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) {
                    $mapping['cascade'] = ['all'];
                }
                // We need to apply our value for non-aggregate roots first, because Doctrine sets a default value for orphanRemoval (see #1127)
                if ($this->isAggregateRoot($mapping['targetEntity'], $className) === false &&
                    $this->isValueObject($mapping['targetEntity'], $className) === false) {
                    $mapping['orphanRemoval'] = true;
                } elseif ($oneToOneAnnotation->orphanRemoval !== null) {
                    $mapping['orphanRemoval'] = $oneToOneAnnotation->orphanRemoval;
                }
                $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnotation->fetch);
                $metadata->mapOneToOne($mapping);
            } elseif ($oneToManyAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OneToMany::class)) {
                $mapping['mappedBy'] = $oneToManyAnnotation->mappedBy;
                if ($oneToManyAnnotation->targetEntity !== null) {
                    $mapping['targetEntity'] = $oneToManyAnnotation->targetEntity;
                } elseif (isset($propertyMetaData['elementType'])) {
                    $mapping['targetEntity'] = $propertyMetaData['elementType'];
                }
                if ($oneToManyAnnotation->cascade !== null) {
                    $mapping['cascade'] = $oneToManyAnnotation->cascade;
                } elseif ($this->isValueObject($mapping['targetEntity'], $className)) {
                    $mapping['cascade'] = ['persist'];
                } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) {
                    $mapping['cascade'] = ['all'];
                }
                $mapping['indexBy'] = $oneToManyAnnotation->indexBy;
                // We need to apply our value for non-aggregate roots first, because Doctrine sets a default value for orphanRemoval (see #1127)
                if ($this->isAggregateRoot($mapping['targetEntity'], $className) === false &&
                    $this->isValueObject($mapping['targetEntity'], $className) === false) {
                    $mapping['orphanRemoval'] = true;
                } elseif ($oneToManyAnnotation->orphanRemoval !== null) {
                    $mapping['orphanRemoval'] = $oneToManyAnnotation->orphanRemoval;
                }
                $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnotation->fetch);

                if ($orderByAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OrderBy::class)) {
                    $mapping['orderBy'] = $orderByAnnotation->value;
                }

                $metadata->mapOneToMany($mapping);
            } elseif ($manyToOneAnnotation = $this->reader->getPropertyAnnotation($property, ORM\ManyToOne::class)) {
                if ($this->reader->getPropertyAnnotation($property, ORM\Id::class) !== null) {
                    $mapping['id'] = true;
                }
                if ($manyToOneAnnotation->targetEntity !== null) {
                    $mapping['targetEntity'] = $manyToOneAnnotation->targetEntity;
                }

                $mapping['joinColumns'] = $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property);
                if ($manyToOneAnnotation->cascade !== null) {
                    $mapping['cascade'] = $manyToOneAnnotation->cascade;
                } elseif ($this->isValueObject($mapping['targetEntity'], $className)) {
                    $mapping['cascade'] = ['persist'];
                } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) {
                    $mapping['cascade'] = ['all'];
                }
                $mapping['inversedBy'] = $manyToOneAnnotation->inversedBy;
                $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnotation->fetch);
                $metadata->mapManyToOne($mapping);
            } elseif ($manyToManyAnnotation = $this->reader->getPropertyAnnotation($property, ORM\ManyToMany::class)) {
                if ($manyToManyAnnotation->targetEntity !== null) {
                    $mapping['targetEntity'] = $manyToManyAnnotation->targetEntity;
                } elseif (isset($propertyMetaData['elementType'])) {
                    $mapping['targetEntity'] = $propertyMetaData['elementType'];
                }
                /** @var ORM\JoinTable $joinTableAnnotation */
                if ($joinTableAnnotation = $this->reader->getPropertyAnnotation($property, ORM\JoinTable::class)) {
                    $joinTable = $this->evaluateJoinTableAnnotation($joinTableAnnotation, $property, $className, $mapping);
                } else {
                    $joinColumns = [
                        [
                            'name' => null,
                            'referencedColumnName' => null,
                        ]
                    ];

                    $joinTable = [
                        'name' => $this->inferJoinTableNameFromClassAndPropertyName($className, $property->getName()),
                        'joinColumns' => $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property, self::MAPPING_MM_REGULAR),
                        'inverseJoinColumns' => $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property)
                    ];
                }

                $mapping['joinTable'] = $joinTable;
                $mapping['mappedBy'] = $manyToManyAnnotation->mappedBy;
                $mapping['inversedBy'] = $manyToManyAnnotation->inversedBy;
                if ($manyToManyAnnotation->cascade !== null) {
                    $mapping['cascade'] = $manyToManyAnnotation->cascade;
                } elseif ($this->isValueObject($mapping['targetEntity'], $className)) {
                    $mapping['cascade'] = ['persist'];
                } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) {
                    $mapping['cascade'] = ['all'];
                }
                $mapping['indexBy'] = $manyToManyAnnotation->indexBy;
                $mapping['orphanRemoval'] = $manyToManyAnnotation->orphanRemoval;
                $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnotation->fetch);

                if ($orderByAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OrderBy::class)) {
                    $mapping['orderBy'] = $orderByAnnotation->value;
                }

                $metadata->mapManyToMany($mapping);
            } elseif ($embeddedAnnotation = $this->reader->getPropertyAnnotation($property, ORM\Embedded::class)) {
                if ($embeddedAnnotation->class !== null) {
                    $mapping['class'] = $embeddedAnnotation->class;
                } else {
                    // This will not happen currently, because "class" argument is required. It would be nice if that could be changed though.
                    $mapping['class'] = $mapping['targetEntity'];
                }
                $mapping['columnPrefix'] = $embeddedAnnotation->columnPrefix;
                $metadata->mapEmbedded($mapping);
            } else {
                $mapping['nullable'] = false;

                /** @var ORM\Column $columnAnnotation */
                if ($columnAnnotation = $this->reader->getPropertyAnnotation($property, ORM\Column::class)) {
                    $mapping = $this->addColumnToMappingArray($columnAnnotation, $mapping);
                }

                if (!isset($mapping['type'])) {
                    switch ($propertyMetaData['type']) {
                        case 'DateTime':
                            $mapping['type'] = 'datetime';
                            break;
                        case 'DateTimeImmutable':
                            $mapping['type'] = 'datetime_immutable';
                            break;
                        case 'string':
                        case 'integer':
                        case 'boolean':
                        case 'float':
                        case 'array':
                            $mapping['type'] = $propertyMetaData['type'];
                            break;
                        default:
                            if (strpos($propertyMetaData['type'], '\\') !== false) {
                                if ($this->reflectionService->isClassAnnotatedWith($propertyMetaData['type'], Flow\ValueObject::class)) {
                                    $valueObjectAnnotation = $this->reflectionService->getClassAnnotation($propertyMetaData['type'], Flow\ValueObject::class);
                                    if ($valueObjectAnnotation->embedded === true) {
                                        $mapping['class'] = $propertyMetaData['type'];
                                        $mapping['columnPrefix'] = $mapping['columnName'];
                                        $metadata->mapEmbedded($mapping);
                                        // Leave switch and continue with next property
                                        continue 2;
                                    }
                                    $mapping['type'] = 'object';
                                } elseif (class_exists($propertyMetaData['type'])) {
                                    throw ORM\MappingException::missingRequiredOption($property->getName(), 'OneToOne', sprintf('The property "%s" in class "%s" has a non standard data type and doesn\'t define the type of the relation. You have to use one of these annotations: @OneToOne, @OneToMany, @ManyToOne, @ManyToMany', $property->getName(), $className));
                                }
                            } else {
                                throw ORM\MappingException::propertyTypeIsRequired($className, $property->getName());
                            }
                    }
                }

                if ($this->reader->getPropertyAnnotation($property, ORM\Id::class) !== null) {
                    $mapping['id'] = true;
                }

                if ($generatedValueAnnotation = $this->reader->getPropertyAnnotation($property, ORM\GeneratedValue::class)) {
                    $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . strtoupper($generatedValueAnnotation->strategy)));
                }

                if ($this->reflectionService->isPropertyAnnotatedWith($className, $property->getName(), ORM\Version::class)) {
                    $metadata->setVersionMapping($mapping);
                }

                $metadata->mapField($mapping);

                // Check for SequenceGenerator/TableGenerator definition
                if ($seqGeneratorAnnotation = $this->reader->getPropertyAnnotation($property, ORM\SequenceGenerator::class)) {
                    $metadata->setSequenceGeneratorDefinition([
                        'sequenceName' => $seqGeneratorAnnotation->sequenceName,
                        'allocationSize' => $seqGeneratorAnnotation->allocationSize,
                        'initialValue' => $seqGeneratorAnnotation->initialValue
                    ]);
                } elseif ($this->reader->getPropertyAnnotation($property, ORM\TableGenerator::class) !== null) {
                    throw ORM\MappingException::tableIdGeneratorNotImplemented($className);
                } elseif ($customGeneratorAnnotation = $this->reader->getPropertyAnnotation($property, ORM\CustomIdGenerator::class)) {
                    $metadata->setCustomGeneratorDefinition([
                        'class' => $customGeneratorAnnotation->class
                    ]);
                }
            }

            // Evaluate @Cache annotation
            if (($cacheAnnotation = $this->reader->getPropertyAnnotation($property, ORM\Cache::class)) !== null) {
                $metadata->enableAssociationCache($mapping['fieldName'], [
                    'usage'         => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnotation->usage),
                    'region'        => $cacheAnnotation->region,
                ]);
            }
        }
    }
524143
static function annotationClass($name)
	{
		if (!AnnotationRegistry::loadAnnotationClass($name)) {
			throw new \Doctrine\Common\Annotations\AnnotationException('Annotation ' . $name . ' - not exists');
		}

		return new $name;
	}