Populates the discriminator value of the given metadata (if not set) by iterating over discriminator
map classes and looking for a fitting one.

@param ClassMetadata $metadata

@return void

@throws MappingException
517991
private function resolveDiscriminatorValue(ClassMetadata $metadata)
    {
        if ($metadata->discriminatorValue
            || ! $metadata->discriminatorMap
            || $metadata->isMappedSuperclass
            || ! $metadata->reflClass
            || $metadata->reflClass->isAbstract()
        ) {
            return;
        }

        // minor optimization: avoid loading related metadata when not needed
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
            if ($discriminatorClass === $metadata->name) {
                $metadata->discriminatorValue = $discriminatorValue;

                return;
            }
        }

        // iterate over discriminator mappings and resolve actual referenced classes according to existing metadata
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
            if ($metadata->name === $this->getMetadataFor($discriminatorClass)->getName()) {
                $metadata->discriminatorValue = $discriminatorValue;

                return;
            }
        }

        throw MappingException::mappedClassNotPartOfDiscriminatorMap($metadata->name, $metadata->rootEntityName);
    }
1163221
protected function dispatchClassMetadataLoadedEvent(ClassMetadataInterface $classMetadata): void
    {
        if (null === $this->eventDispatcher) {
            return;
        }

        $this->eventDispatcher->dispatch(
            ClassMetadataLoadedEvent::LOADED_EVENT,
            new ClassMetadataLoadedEvent($classMetadata)
        );
    }
225839
private function setMetadata(array $metadata)
    {
        foreach($metadata as $key => &$partial) {
            $this->assertArrayOrScalar($partial, $key);
        }

        $this->metadata = new ArrayReader($metadata);
    }
1253203
private function buildFieldMappings(Mapping\ClassMetadata $metadata)
    {
        $tableName      = $metadata->getTableName();
        $columns        = $this->tables[$tableName]->getColumns();
        $primaryKeys    = $this->getTablePrimaryKeys($this->tables[$tableName]);
        $foreignKeys    = $this->getTableForeignKeys($this->tables[$tableName]);
        $allForeignKeys = [];

        foreach ($foreignKeys as $foreignKey) {
            $allForeignKeys = array_merge($allForeignKeys, $foreignKey->getLocalColumns());
        }

        $ids = [];

        foreach ($columns as $column) {
            if (in_array($column->getName(), $allForeignKeys, true)) {
                continue;
            }

            $fieldName     = $this->getFieldNameForColumn($tableName, $column->getName(), false);
            $fieldMetadata = $this->convertColumnAnnotationToFieldMetadata($tableName, $column, $fieldName);

            if ($primaryKeys && in_array($column->getName(), $primaryKeys, true)) {
                $fieldMetadata->setPrimaryKey(true);

                $ids[] = $fieldMetadata;
            }

            $metadata->addProperty($fieldMetadata);
        }

        // We need to check for the columns here, because we might have associations as id as well.
        if ($ids && count($primaryKeys) === 1) {
            $ids[0]->setValueGenerator(new Mapping\ValueGeneratorMetadata(Mapping\GeneratorType::AUTO));
        }
    }
1087181
protected function setSearch(Metadata\EntityMetadata $metadata, array $mapping)
    {
        $clientKey = isset($mapping['key']) ? $mapping['key'] : null;
        if (null === $clientKey) {
            // Search is not enabled for this model.
            return $metadata;
        }

        $factory = $this->getSearchMetadataFactory($clientKey);

        $search = $factory->createInstance($mapping);

        $metadata->setSearch($search);
        return $metadata;
    }
148237
public function setDefaultDiscriminatorValue(?string $defaultDiscriminatorValue) : void
    {
        if ($this->isFile) {
            throw MappingException::discriminatorNotAllowedForGridFS($this->name);
        }

        if ($defaultDiscriminatorValue === null) {
            $this->defaultDiscriminatorValue = null;

            return;
        }

        if (! array_key_exists($defaultDiscriminatorValue, $this->discriminatorMap)) {
            throw MappingException::invalidDiscriminatorValue($defaultDiscriminatorValue, $this->name);
        }

        $this->defaultDiscriminatorValue = $defaultDiscriminatorValue;
    }
780799
private function validateDatabase(EntityMetadata $metadata)
    {
        $persistence = $metadata->persistence;
        if (false === $metadata->isChildEntity() && (empty($persistence->db) || empty($persistence->collection))) {
            throw MetadataException::invalidMetadata($metadata->type, 'The persistence database and collection names cannot be empty.');
        }
    }
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,
            ]);
        }
    }
1323352
public function loadMetadataForClass($className, ClassMetadata $metadata)
    {
        $class = $metadata->getReflectionClass();
        if (! $class) {
            // this happens when running annotation driver in combination with
            // static reflection services. This is not the nicest fix
            $class = new \ReflectionClass($metadata->name);
        }

        $entityAnnot = $this->reader->getClassAnnotation($class, 'Doctrine\KeyValueStore\Mapping\Annotations\Entity');
        if (! $entityAnnot) {
            throw new \InvalidArgumentException($metadata->name . ' is not a valid key-value-store entity.');
        }
        $metadata->storageName = $entityAnnot->storageName;

        // Evaluate annotations on properties/fields
        foreach ($class->getProperties() as $property) {
            $idAnnot        = $this->reader->getPropertyAnnotation(
                $property,
                'Doctrine\KeyValueStore\Mapping\Annotations\Id'
            );
            $transientAnnot = $this->reader->getPropertyAnnotation(
                $property,
                'Doctrine\KeyValueStore\Mapping\Annotations\Transient'
            );
            if ($idAnnot) {
                $metadata->mapIdentifier($property->getName());
            } elseif ($transientAnnot) {
                $metadata->skipTransientField($property->getName());
            } else {
                $metadata->mapField(['fieldName' => $property->getName()]);
            }
        }
    }
240607
private function instantiateFromMetadata(Metadata $metadata)
    {
        $class = $metadata->getClass();

        if (!class_exists($class)) {
            throw new \RuntimeException(sprintf(
                'Document class "%s" does not exist', $class
            ));
        }

        $document = new $class();

        return $document;
    }
360227
public function setDiscriminatorColumn($columnDef)
    {
        if ($columnDef !== null) {
            if ( ! isset($columnDef['name'])) {
                throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name);
            }

            if (isset($this->fieldNames[$columnDef['name']])) {
                throw MappingException::duplicateColumnName($this->name, $columnDef['name']);
            }

            if ( ! isset($columnDef['fieldName'])) {
                $columnDef['fieldName'] = $columnDef['name'];
            }

            if ( ! isset($columnDef['type'])) {
                $columnDef['type'] = "string";
            }

            if (in_array($columnDef['type'], array("boolean", "array", "object", "datetime", "time", "date"))) {
                throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']);
            }

            $this->discriminatorColumn = $columnDef;
        }
    }
212575
public function setDiscriminatorMap(array $map)
    {
        foreach ($map as $value => $className) {
            if (strpos($className, '\\') === false && strlen($this->namespace)) {
                $className = $this->namespace . '\\' . $className;
            }
            $this->discriminatorMap[$value] = $className;
            if ($this->name == $className) {
                $this->discriminatorValue = $value;
            } else {
                if ( ! class_exists($className)) {
                    throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
                }
                if (is_subclass_of($className, $this->name)) {
                    $this->subClasses[] = $className;
                }
            }
        }
    }
623616
private function getFieldFilter(ClassMetadata $metadata, array $fields)
    {
        /* @var \Doctrine\ORM\Mapping\ClassMetadata $metadata */
        $filters = array();
        foreach ($fields as $field) {
            $fieldName = $this->getFieldName($metadata, $field);
            try {
                $filters[] = $metadata->getFieldMapping($fieldName);
            } catch (\Exception $ex) {
                $mapping = $metadata->getAssociationMapping($fieldName);
                $associationMatadata = $this->entityManager->getClassMetadata($mapping['targetEntity']);
                $associationFields = $associationMatadata->getFieldNames();
                $associationIdentifier = $associationMatadata->getIdentifierFieldNames();
                $associationFields = array_values(array_filter(
                    $associationFields,
                    function ($value) use ($associationIdentifier) {
                        return !in_array($value, $associationIdentifier);
                    }
                ));
                if ($associationFields) {
                    $filters[] = array_merge(array(
                        'join' => true,
                        'join_field' => $fieldName,
                        'join_alias' => $this->getAlias(),
                    ), $associationMatadata->getFieldMapping($associationFields[0]));
                }
            }
        }

        return $filters;
    }
538729
public function setDiscriminatorColumn(DiscriminatorColumnMetadata $discriminatorColumn) : void
    {
        if (isset($this->fieldNames[$discriminatorColumn->getColumnName()])) {
            throw MappingException::duplicateColumnName($this->className, $discriminatorColumn->getColumnName());
        }

        $discriminatorColumn->setTableName($discriminatorColumn->getTableName() ?? $this->getTableName());

        $allowedTypeList = ['boolean', 'array', 'object', 'datetime', 'time', 'date'];

        if (in_array($discriminatorColumn->getTypeName(), $allowedTypeList, true)) {
            throw MappingException::invalidDiscriminatorColumnType($discriminatorColumn->getTypeName());
        }

        $this->discriminatorColumn = $discriminatorColumn;
    }
848011
public function loadMetadataForClass($className, ClassMetadata $metadata)
    {
        if (!\in_array(DatabaseEntityInterface::class, \class_implements($className))) {
            $repositoryName = $this->entityRepositoryMapping->getRepositoryByEntity($className);
            $instantiator = new Instantiator();

            /** @var RepositoryInterface $repository */
            $repository = $instantiator->instantiate($repositoryName);
            $classMetaDataBuilder = new ClassMetadataBuilder($metadata);
            $repository->loadMetadata($classMetaDataBuilder);

            return;
        }

        $classMetaDataBuilder = new ClassMetadataBuilder($metadata);
        $className::loadMetadata($classMetaDataBuilder);
    }
585174
protected static function validatorMetaForPropertyUrl(ValidatorClassMetaData $metadata): void
    {
        $metadata->addPropertyConstraint(
            UrlFieldInterface::PROP_URL,
            new Url([
                        'relativeProtocol' => true,
                        'protocols'        => ['http', 'https'],
                    ])
        );
    }
1007822
private function attachDiscriminatorColumn(
        array $classAnnotations,
        ReflectionClass $reflectionClass,
        Mapping\ClassMetadata $metadata
    ) : void {
        $discriminatorColumn = new Mapping\DiscriminatorColumnMetadata();

        $discriminatorColumn->setTableName($metadata->getTableName());
        $discriminatorColumn->setColumnName('dtype');
        $discriminatorColumn->setType(Type::getType('string'));
        $discriminatorColumn->setLength(255);

        // Evaluate DiscriminatorColumn annotation
        if (isset($classAnnotations[Annotation\DiscriminatorColumn::class])) {
            /** @var Annotation\DiscriminatorColumn $discriminatorColumnAnnotation */
            $discriminatorColumnAnnotation = $classAnnotations[Annotation\DiscriminatorColumn::class];
            $typeName                      = ! empty($discriminatorColumnAnnotation->type)
                ? $discriminatorColumnAnnotation->type
                : 'string';

            $discriminatorColumn->setType(Type::getType($typeName));
            $discriminatorColumn->setColumnName($discriminatorColumnAnnotation->name);

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

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

        $metadata->setDiscriminatorColumn($discriminatorColumn);

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

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