Reads annotations for a selected property in the class

@param ReflectionProperty $property
@param ClassMetadata $metadata
356283
private function readProperty($property, $metadata)
    {
        $reflClass = $metadata->getReflectionClass();
        
        // Skip if this property is not from this class
        if ($property->getDeclaringClass()->getName()
            != $metadata->getClassName()
        ) {
            return;
        }

        //Iterate over all annotations
        foreach($this->reader->getPropertyAnnotations($property) as $rule) {

            //Skip is its not a rule
            if ( ! $rule instanceof Rules\Rule ) continue;
            
            //Add Rule
            $metadata->addPropertyRule($property->getName(), $rule);

        }

    }
674460
public function loadMetadataForClass($className, ClassMetadata $metadata)
    {
        /**
         * This is the actual type we have at this point, but we cannot change the
         * signature due to inheritance.
         *
         * @var ORM\ClassMetadata $metadata
         */

        try {
            $class = $metadata->getReflectionClass();
            $classSchema = $this->getClassSchema($class->getName());
            $classAnnotations = $this->reader->getClassAnnotations($class);
        } catch (ClassSchemaNotFoundException $exception) {
            throw new ORM\MappingException(sprintf('Failure while fetching class schema class "%s": %s', $metadata->getName(), $exception->getMessage()), 1542792708, $exception);
        }

        // Evaluate Entity annotation
        if (isset($classAnnotations[ORM\MappedSuperclass::class])) {
            $mappedSuperclassAnnotation = $classAnnotations[ORM\MappedSuperclass::class];
            if ($mappedSuperclassAnnotation->repositoryClass !== null) {
                $metadata->setCustomRepositoryClass($mappedSuperclassAnnotation->repositoryClass);
            }
            $metadata->isMappedSuperclass = true;
        } elseif (isset($classAnnotations[Flow\Entity::class]) || isset($classAnnotations[ORM\Entity::class])) {
            $entityAnnotation = isset($classAnnotations[Flow\Entity::class]) ? $classAnnotations[Flow\Entity::class] : $classAnnotations[ORM\Entity::class];
            if ($entityAnnotation->repositoryClass !== null) {
                $metadata->setCustomRepositoryClass($entityAnnotation->repositoryClass);
            } elseif ($classSchema->getRepositoryClassName() !== null) {
                if ($this->reflectionService->isClassImplementationOf($classSchema->getRepositoryClassName(), \Doctrine\ORM\EntityRepository::class)) {
                    $metadata->setCustomRepositoryClass($classSchema->getRepositoryClassName());
                }
            }
            if ($entityAnnotation->readOnly) {
                $metadata->markReadOnly();
            }
        } elseif (isset($classAnnotations[Flow\ValueObject::class])) {
            $valueObjectAnnotation = $classAnnotations[Flow\ValueObject::class];
            if ($valueObjectAnnotation->embedded === true) {
                $metadata->isEmbeddedClass = true;
            } else {
                // also ok... but we make it read-only
                $metadata->markReadOnly();
            }
        } elseif (isset($classAnnotations[ORM\Embeddable::class])) {
            $metadata->isEmbeddedClass = true;
        } else {
            throw ORM\MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
        }

        // Evaluate Table annotation
        $primaryTable = [];
        if (isset($classAnnotations[ORM\Table::class])) {
            $tableAnnotation = $classAnnotations[ORM\Table::class];
            $primaryTable = [
                'name' => $tableAnnotation->name,
                'schema' => $tableAnnotation->schema
            ];

            if ($tableAnnotation->indexes !== null) {
                foreach ($tableAnnotation->indexes as $indexAnnotation) {
                    $index = ['columns' => $indexAnnotation->columns];
                    if (!empty($indexAnnotation->flags)) {
                        $index['flags'] = $indexAnnotation->flags;
                    }
                    if (!empty($indexAnnotation->options)) {
                        $index['options'] = $indexAnnotation->options;
                    }
                    if (!empty($indexAnnotation->name)) {
                        $primaryTable['indexes'][$indexAnnotation->name] = $index;
                    } else {
                        $primaryTable['indexes'][] = $index;
                    }
                }
            }

            if ($tableAnnotation->uniqueConstraints !== null) {
                foreach ($tableAnnotation->uniqueConstraints as $uniqueConstraint) {
                    $uniqueConstraint = ['columns' => $uniqueConstraint->columns];
                    if (!empty($uniqueConstraint->options)) {
                        $uniqueConstraint['options'] = $uniqueConstraint->options;
                    }
                    if (!empty($uniqueConstraint->name)) {
                        $primaryTable['uniqueConstraints'][$uniqueConstraint->name] = $uniqueConstraint;
                    } else {
                        $primaryTable['uniqueConstraints'][] = $uniqueConstraint;
                    }
                }
            }

            if ($tableAnnotation->options !== null) {
                $primaryTable['options'] = $tableAnnotation->options;
            }
        }
        if (!isset($classAnnotations[ORM\Embeddable::class])
            && !isset($primaryTable['name'])) {
            $className = $classSchema->getClassName();
            $primaryTable['name'] = $this->inferTableNameFromClassName($className);
        }

        // Evaluate @Cache annotation
        if (isset($classAnnotations[ORM\Cache::class])) {
            $cacheAnnotation = $classAnnotations[ORM\Cache::class];
            $cacheMap   = [
                'region' => $cacheAnnotation->region,
                'usage'  => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnotation->usage),
            ];

            $metadata->enableCache($cacheMap);
        }

        // Evaluate NamedNativeQueries annotation
        if (isset($classAnnotations[ORM\NamedNativeQueries::class])) {
            $namedNativeQueriesAnnotation = $classAnnotations[ORM\NamedNativeQueries::class];

            foreach ($namedNativeQueriesAnnotation->value as $namedNativeQuery) {
                $metadata->addNamedNativeQuery([
                    'name' => $namedNativeQuery->name,
                    'query' => $namedNativeQuery->query,
                    'resultClass' => $namedNativeQuery->resultClass,
                    'resultSetMapping' => $namedNativeQuery->resultSetMapping,
                ]);
            }
        }

        // Evaluate SqlResultSetMappings annotation
        if (isset($classAnnotations[ORM\SqlResultSetMappings::class])) {
            $sqlResultSetMappingsAnnotation = $classAnnotations[ORM\SqlResultSetMappings::class];

            foreach ($sqlResultSetMappingsAnnotation->value as $resultSetMapping) {
                $entities = [];
                $columns = [];
                foreach ($resultSetMapping->entities as $entityResultAnnotation) {
                    $entityResult = [
                        'fields' => [],
                        'entityClass' => $entityResultAnnotation->entityClass,
                        'discriminatorColumn' => $entityResultAnnotation->discriminatorColumn,
                    ];

                    foreach ($entityResultAnnotation->fields as $fieldResultAnnotation) {
                        $entityResult['fields'][] = [
                            'name' => $fieldResultAnnotation->name,
                            'column' => $fieldResultAnnotation->column
                        ];
                    }

                    $entities[] = $entityResult;
                }

                foreach ($resultSetMapping->columns as $columnResultAnnotation) {
                    $columns[] = [
                        'name' => $columnResultAnnotation->name,
                    ];
                }

                $metadata->addSqlResultSetMapping([
                    'name' => $resultSetMapping->name,
                    'entities' => $entities,
                    'columns' => $columns
                ]);
            }
        }

        // Evaluate NamedQueries annotation
        if (isset($classAnnotations[ORM\NamedQueries::class])) {
            $namedQueriesAnnotation = $classAnnotations[ORM\NamedQueries::class];

            if (!is_array($namedQueriesAnnotation->value)) {
                throw new \UnexpectedValueException('@ORM\NamedQueries should contain an array of @ORM\NamedQuery annotations.');
            }

            foreach ($namedQueriesAnnotation->value as $namedQuery) {
                if (!($namedQuery instanceof ORM\NamedQuery)) {
                    throw new \UnexpectedValueException('@ORM\NamedQueries should contain an array of @ORM\NamedQuery annotations.');
                }
                $metadata->addNamedQuery([
                    'name' => $namedQuery->name,
                    'query' => $namedQuery->query
                ]);
            }
        }

        // Evaluate InheritanceType annotation
        if (isset($classAnnotations[ORM\InheritanceType::class])) {
            $inheritanceTypeAnnotation = $classAnnotations[ORM\InheritanceType::class];
            $inheritanceType = constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($inheritanceTypeAnnotation->value));

            if ($inheritanceType !== ORM\ClassMetadata::INHERITANCE_TYPE_NONE) {

                // Evaluate DiscriminatorColumn annotation
                if (isset($classAnnotations[ORM\DiscriminatorColumn::class])) {
                    $discriminatorColumnAnnotation = $classAnnotations[ORM\DiscriminatorColumn::class];
                    $discriminatorColumn = [
                        'name' => $discriminatorColumnAnnotation->name,
                        'type' => $discriminatorColumnAnnotation->type,
                        'length' => $discriminatorColumnAnnotation->length,
                        'columnDefinition' => $discriminatorColumnAnnotation->columnDefinition
                    ];
                } else {
                    $discriminatorColumn = [
                        'name' => 'dtype', 'type' => 'string', 'length' => 255
                    ];
                }

                // Evaluate DiscriminatorMap annotation
                if (isset($classAnnotations[ORM\DiscriminatorMap::class])) {
                    $discriminatorMapAnnotation = $classAnnotations[ORM\DiscriminatorMap::class];
                    $discriminatorMap = $discriminatorMapAnnotation->value;
                } else {
                    $discriminatorMap = [];
                    $subclassNames = $this->reflectionService->getAllSubClassNamesForClass($className);
                    if (!$this->reflectionService->isClassAbstract($className)) {
                        $mappedClassName = strtolower(str_replace('Domain_Model_', '', str_replace('\\', '_', $className)));
                        $discriminatorMap[$mappedClassName] = $className;
                    }
                    foreach ($subclassNames as $subclassName) {
                        $mappedSubclassName = strtolower(str_replace('Domain_Model_', '', str_replace('\\', '_', $subclassName)));
                        $discriminatorMap[$mappedSubclassName] = $subclassName;
                    }
                }

                if ($discriminatorMap !== []) {
                    $metadata->setDiscriminatorColumn($discriminatorColumn);
                    $metadata->setDiscriminatorMap($discriminatorMap);
                } else {
                    $inheritanceType = ORM\ClassMetadata::INHERITANCE_TYPE_NONE;
                }
            }

            $metadata->setInheritanceType($inheritanceType);
        }

        // Evaluate DoctrineChangeTrackingPolicy annotation
        if (isset($classAnnotations[ORM\ChangeTrackingPolicy::class])) {
            $changeTrackingAnnotation = $classAnnotations[ORM\ChangeTrackingPolicy::class];
            $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . strtoupper($changeTrackingAnnotation->value)));
        } else {
            $metadata->setChangeTrackingPolicy(ORM\ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT);
        }

        // Evaluate annotations on properties/fields
        try {
            $this->evaluatePropertyAnnotations($metadata);
        } catch (ORM\MappingException $exception) {
            throw new ORM\MappingException(sprintf('Failure while evaluating property annotations for class "%s": %s', $metadata->getName(), $exception->getMessage()), 1382003497, $exception);
        }

        // build unique index for table
        if (!isset($classAnnotations[ORM\Embeddable::class])
            && !isset($primaryTable['uniqueConstraints'])) {
            $idProperties = array_keys($classSchema->getIdentityProperties());
            if (array_diff($idProperties, $metadata->getIdentifierFieldNames()) !== []) {
                $uniqueIndexName = $this->truncateIdentifier('flow_identity_' . $primaryTable['name']);
                foreach ($idProperties as $idProperty) {
                    $primaryTable['uniqueConstraints'][$uniqueIndexName]['columns'][] = isset($metadata->columnNames[$idProperty]) ? $metadata->columnNames[$idProperty] : strtolower($idProperty);
                }
            }
        }

        $metadata->setPrimaryTable($primaryTable);

        // Evaluate AssociationOverrides annotation
        $this->evaluateOverridesAnnotations($classAnnotations, $metadata);

        // Evaluate EntityListeners annotation
        $this->evaluateEntityListenersAnnotation($class, $metadata, $classAnnotations);

        // Evaluate @HasLifecycleCallbacks annotation
        $this->evaluateLifeCycleAnnotations($class, $metadata);
    }
171923
private function isBoomgoProperty(\ReflectionProperty $property)
    {
        $propertyName = $property->getName();
        $className = $property->getDeclaringClass()->getName();

        $annotationTag = substr_count($property->getDocComment(), $this->getLocalAnnotation());
        if (0 < $annotationTag) {
            if (1 === $annotationTag) {
                return true;
            }

            throw new \RuntimeException(sprintf('Boomgo annotation tag should occur only once for "%s->%s"', $className, $propertyName));
        }

        return false;
    }
422687
protected function processPropertiesParsing(\ReflectionClass $reflectedClass)
    {
        $metadata = array();

        $reflectedProperties = $reflectedClass->getProperties();

        foreach ($reflectedProperties as $reflectedProperty) {
            if ($this->isBoomgoProperty($reflectedProperty)) {
                $propertyMetadata = $this->parseMetadataProperty($reflectedProperty);
                $metadata['definitions'][$reflectedProperty->getName()] = $propertyMetadata;
            }
        }

        return $metadata;
    }
1254372
public static function hasPropertyAnnotation(\ReflectionProperty $property, $annotationClass, AnnotationReader $reader)
    {
        if (null === self::getPropertyAnnotation($property, $annotationClass, $reader)) {
            return false;
        }

        return true;
    }
987217
private function getMetaFieldAnnotationData($property, $directory)
    {
        /** @var MetaField $annotation */
        $annotation = $this->reader->getPropertyAnnotation($property, self::ID_ANNOTATION);
        $annotation = $annotation ?: $this->reader->getPropertyAnnotation($property, self::PARENT_ANNOTATION);
        $annotation = $annotation ?: $this->reader->getPropertyAnnotation($property, self::ROUTING_ANNOTATION);
        $annotation = $annotation ?: $this->reader->getPropertyAnnotation($property, self::VERSION_ANNOTATION);

        if ($annotation === null) {
            return null;
        }

        $data = [
            'name' => $annotation->getName(),
            'settings' => $annotation->getSettings(),
        ];

        if ($annotation instanceof ParentDocument) {
            $data['settings']['type'] = $this->getDocumentType($annotation->class, $directory);
        }

        return $data;
    }
502124
public function processClassMetadata(ClassMetadata $metadata, $property, $prefix)
    {
        if (in_array($metadata->getName(), $this->processedClasses)) {
            return;
        }

        $metadata->mapEmbedded([
            'fieldName'    => $property,
            'class'        => $this->embeddableMetadata->getName(),
            'columnPrefix' => empty($prefix) ? false : $prefix,
        ]);

        $metadata->inlineEmbeddable($property, $this->embeddableMetadata);

        $this->processedClasses[] = $metadata->getName();
    }
826328
public function loadMetadataForClass($className, ClassMetadata $metadata)
    {
        if (false === $metadata instanceof OdmClassMetadata) {
            throw new MappingException(
                sprintf('Metadata is of class "%s" instead of "%s"', get_class($metadata), OdmClassMetadata::class)
            );
        }

        if (false === isset($this->classMap[$className])) {
            throw new MappingException(
                sprintf('No configured mapping for document "%s"', $className)
            );
        }

        $mappingClassName = $this->classMap[$className];

        if (false === ($mapping = new $mappingClassName()) instanceof OdmMappingInterface) {
            throw new MappingException('Class %s does not implement the OdmMappingInterface');
        }

        /* @var OdmMappingInterface $mapping */
        /* @var OdmClassMetadata $metadata */

        $mapping->configureMapping($metadata);
    }
1119673
protected function parseNodes(\ReflectionClass $class, ClassMetadata $metadata, $config)
    {
        if (!isset($config['nodes'])) {
            return;
        }

        if (!is_array($config)) {
            throw new \RuntimeException(sprintf('Invalid YAML configuration for "%s" : "properties" property need to be an array.', $metadata->name));
        }

        foreach ($config['nodes'] as $property => $nodeProperties) {
            foreach ($nodeProperties as $nodeProperty) {
                if (!isset($nodeProperty['namespace']) || !isset($nodeProperty['tag'])) {
                    throw new \RuntimeException(sprintf('Invalid YAML configuration for "%s" : "namespace" and "tag" are required.', $metadata->name));
                }

                $node = new Node([
                    'namespace' => $nodeProperty['namespace'],
                    'tag' => $nodeProperty['tag'],
                ]);

                if ($class->hasProperty($property)) {
                    $metadata->addGraphMetadata($node, new PropertyMetadata($class->name, $property));
                }

                if ($class->hasMethod($property)) {
                    $metadata->addGraphMetadata($node, new MethodMetadata($class->name, $property));
                }
            }
        }
    }
385935
private function collectAttributeTypeMetadata(
        PropertyMetadataBuilder $metadata,
        Attribute $attribute
    ) : void {
        $type = $attribute->type;

        // handle the case if the property type is mixed
        if ('mixed' === $type) {
            return;
        }

        if ($attribute->required) {
            $metadata->withBeingRequired();
        }

        // Evaluate type

        // Checks if the property has array<type>
        if (false !== $pos = strpos($type, '<')) {
            $arrayType = substr($type, $pos + 1, -1);

            $metadata->withType(new ArrayType(new MixedType(), $this->createTypeFromName($arrayType)));

            return;
        }

        // Checks if the property has type[]
         if (false !== $pos = strrpos($type, '[')) {
            $arrayType = substr($type, 0, $pos);

            $metadata->withType(new ArrayType(new MixedType(), $this->createTypeFromName($arrayType)));

            return;
        }

        $metadata->withType($this->createTypeFromName($attribute->type));
    }
107603
protected function getPropertiesMeta(ReflectionClass $reflection): array
    {
        $meta = [];
        $properties = $reflection->getProperties(ReflectionProperty::IS_PUBLIC);

        foreach ($properties as $item) {
            $doc = $item->getDocComment();
            $notations = $this->parser->parse($doc);

            if (count($notations) > 0) {
                $meta[$item->getName()] = $notations;
            }
        }

        return $meta;
    }
350036
protected function validateAndCompleteFieldMapping(FieldMetadata $property)
    {
        $fieldName  = $property->getName();
        $columnName = $property->getColumnName();

        if (empty($columnName)) {
            $columnName = $this->namingStrategy->propertyToColumnName($fieldName, $this->className);

            $property->setColumnName($columnName);
        }

        if (! $this->isMappedSuperclass) {
            $property->setTableName($this->getTableName());
        }

        // Check for already declared column
        if (isset($this->fieldNames[$columnName]) ||
            ($this->discriminatorColumn !== null && $this->discriminatorColumn->getColumnName() === $columnName)) {
            throw MappingException::duplicateColumnName($this->className, $columnName);
        }

        // Complete id mapping
        if ($property->isPrimaryKey()) {
            if ($this->versionProperty !== null && $this->versionProperty->getName() === $fieldName) {
                throw MappingException::cannotVersionIdField($this->className, $fieldName);
            }

            if ($property->getType()->canRequireSQLConversion()) {
                throw MappingException::sqlConversionNotAllowedForPrimaryKeyProperties($this->className, $property);
            }

            if (! in_array($fieldName, $this->identifier, true)) {
                $this->identifier[] = $fieldName;
            }
        }

        $this->fieldNames[$columnName] = $fieldName;
    }
179697
private function convertReflectionPropertyToManyToOneAssociationMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $metadata
    ) {
        $className      = $metadata->getClassName();
        $fieldName      = $reflectionProperty->getName();
        $manyToOneAnnot = $propertyAnnotations[Annotation\ManyToOne::class];
        $assocMetadata  = new Mapping\ManyToOneAssociationMetadata($fieldName);
        $targetEntity   = $manyToOneAnnot->targetEntity;

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

        if (! empty($manyToOneAnnot->inversedBy)) {
            $assocMetadata->setInversedBy($manyToOneAnnot->inversedBy);
        }

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

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

        // Check for JoinColumn/JoinColumns annotations
        switch (true) {
            case isset($propertyAnnotations[Annotation\JoinColumn::class]):
                $joinColumnAnnot = $propertyAnnotations[Annotation\JoinColumn::class];

                $assocMetadata->addJoinColumn(
                    $this->convertJoinColumnAnnotationToJoinColumnMetadata($joinColumnAnnot)
                );

                break;

            case isset($propertyAnnotations[Annotation\JoinColumns::class]):
                $joinColumnsAnnot = $propertyAnnotations[Annotation\JoinColumns::class];

                foreach ($joinColumnsAnnot->value as $joinColumnAnnot) {
                    $assocMetadata->addJoinColumn(
                        $this->convertJoinColumnAnnotationToJoinColumnMetadata($joinColumnAnnot)
                    );
                }

                break;
        }

        return $assocMetadata;
    }
1278248
private function guessProperty(ClassMetadata $metadata, $element)
    {
        // Is it the element the actual property
        if ($metadata->hasPropertyMetadata($element)) {
            return $element;
        }

        // Is it a camelized property
        $camelized = $this->camelize($element);
        if ($metadata->hasPropertyMetadata($camelized)) {
            return $camelized;
        }

        return null;
    }
871847
private function convertReflectionPropertyToFieldMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $classMetadata
    ) {
        $className    = $classMetadata->getClassName();
        $fieldName    = $reflectionProperty->getName();
        $columnAnnot  = $propertyAnnotations[Annotation\Column::class];
        $isVersioned  = isset($propertyAnnotations[Annotation\Version::class]);
        $isPrimaryKey = isset($propertyAnnotations[Annotation\Id::class]);

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

        if ($isVersioned && $isPrimaryKey) {
            throw Mapping\MappingException::cannotVersionIdField($className, $fieldName);
        }

        $columnName = empty($columnAnnot->name)
            ? $this->namingStrategy->propertyToColumnName($fieldName, $className)
            : $columnAnnot->name;

        $fieldMetadata = $isVersioned
            ? new Mapping\VersionFieldMetadata($fieldName)
            : new Mapping\FieldMetadata($fieldName);

        $fieldMetadata->setType(Type::getType($columnAnnot->type));
        $fieldMetadata->setColumnName($columnName);
        $fieldMetadata->setScale($columnAnnot->scale);
        $fieldMetadata->setPrecision($columnAnnot->precision);
        $fieldMetadata->setNullable($columnAnnot->nullable);
        $fieldMetadata->setUnique($columnAnnot->unique);

        // Check for Id
        if ($isPrimaryKey) {
            if ($fieldMetadata->getType()->canRequireSQLConversion()) {
                throw Mapping\MappingException::sqlConversionNotAllowedForPrimaryKeyProperties($className, $fieldMetadata);
            }

            $fieldMetadata->setPrimaryKey(true);
        }

        if (! empty($columnAnnot->columnDefinition)) {
            $fieldMetadata->setColumnDefinition($columnAnnot->columnDefinition);
        }

        if (! empty($columnAnnot->length)) {
            $fieldMetadata->setLength($columnAnnot->length);
        }

        // Assign default options
        $customOptions  = $columnAnnot->options ?? [];
        $defaultOptions = [];

        if ($isVersioned) {
            switch ($fieldMetadata->getTypeName()) {
                case 'integer':
                case 'bigint':
                case 'smallint':
                    $defaultOptions['default'] = 1;
                    break;

                case 'datetime':
                    $defaultOptions['default'] = 'CURRENT_TIMESTAMP';
                    break;

                default:
                    if (! isset($customOptions['default'])) {
                        throw Mapping\MappingException::unsupportedOptimisticLockingType($fieldMetadata->getType());
                    }
            }
        }

        $fieldMetadata->setOptions(array_merge($defaultOptions, $customOptions));

        return $fieldMetadata;
    }
1191886
protected function parseAssociation($propertyName, \ReflectionProperty $reflectionProperty, AnnotationBag $propertyAnnotations) {
		if ($propertyAnnotations->has('OneToOne')) {
			$association = new OneToOne($propertyName, $reflectionProperty, $propertyAnnotations);
			
			if ($association->isForeignKey()) {
				$attribute = $association->getAttribute()->getArgument();
				$this->foreignKeys[$attribute] = $propertyName;
			}
			elseif ($association->isCascade())
				$this->references[] = $propertyName;
		}
		elseif ($propertyAnnotations->has('OneToMany')) {
			$association = new OneToMany($propertyName, $reflectionProperty, $propertyAnnotations);
			
			if ($association->isCascade())
				$this->references[] = $propertyName;
		}
		elseif ($propertyAnnotations->has('ManyToOne')) {
			$association = new ManyToOne($propertyName, $reflectionProperty, $propertyAnnotations);
			$attribute = $association->getAttribute()->getArgument();
			$this->foreignKeys[$attribute] = $propertyName;
		}
		elseif ($propertyAnnotations->has('ManyToMany')) {
			$association = new ManyToMany($propertyName, $reflectionProperty, $propertyAnnotations);
			
			if ($association->isCascade())
				$this->references[] = $propertyName;
		}
		
		$this->associations[$propertyName] = $association;
	}
441153
private function mapTranslation(ClassMetadata $metadata): void
    {
        $className = $metadata->name;

        try {
            $resourceMetadata = $this->resourceMetadataRegistry->getByClass($className);
        } catch (\InvalidArgumentException $exception) {
            return;
        }

        /** @var MetadataInterface $translatableResourceMetadata */
        $translatableResourceMetadata = $this->resourceMetadataRegistry->get(str_replace('_translation', '', $resourceMetadata->getAlias()));

        if (!$metadata->hasAssociation('translatable')) {
            $metadata->mapManyToOne([
                'fieldName' => 'translatable',
                'targetEntity' => $translatableResourceMetadata->getClass('model'),
                'inversedBy' => 'translations',
                'joinColumns' => [[
                    'name' => 'translatable_id',
                    'referencedColumnName' => 'id',
                    'onDelete' => 'CASCADE',
                    'nullable' => false,
                ]],
            ]);
        }

        if (!$metadata->hasField('locale')) {
            $metadata->mapField([
                'fieldName' => 'locale',
                'type' => 'string',
                'nullable' => false,
            ]);
        }

        // Map unique index.
        $columns = [
            $metadata->getSingleAssociationJoinColumnName('translatable'),
            'locale',
        ];

        if (!$this->hasUniqueConstraint($metadata, $columns)) {
            $constraints = $metadata->table['uniqueConstraints'] ?? [];

            $constraints[$metadata->getTableName() . '_uniq_trans'] = [
                'columns' => $columns,
            ];

            $metadata->setPrimaryTable([
                'uniqueConstraints' => $constraints,
            ]);
        }
    }