<?php 
/* 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 * 
 * This software consists of voluntary contributions made by many individuals 
 * and is licensed under the MIT license. For more information, see 
 * <http://www.doctrine-project.org>. 
 */ 
 
namespace Doctrine\ORM\Mapping; 
 
use Doctrine\DBAL\Platforms; 
use Doctrine\ORM\EntityManagerInterface; 
use Doctrine\ORM\Event\LoadClassMetadataEventArgs; 
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs; 
use Doctrine\ORM\Events; 
use Doctrine\ORM\Id\BigIntegerIdentityGenerator; 
use Doctrine\ORM\Id\IdentityGenerator; 
use Doctrine\ORM\ORMException; 
use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory; 
use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface; 
use Doctrine\Persistence\Mapping\Driver\MappingDriver; 
use Doctrine\Persistence\Mapping\ReflectionService; 
use ReflectionClass; 
use ReflectionException; 
use function assert; 
use function interface_exists; 
 
/** 
 * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the 
 * metadata mapping information of a class which describes how a class should be mapped 
 * to a relational database. 
 * 
 * @since   2.0 
 * @author  Benjamin Eberlei <kontakt@beberlei.de> 
 * @author  Guilherme Blanco <guilhermeblanco@hotmail.com> 
 * @author  Jonathan Wage <jonwage@gmail.com> 
 * @author  Roman Borschel <roman@code-factory.org> 
 */ 
class ClassMetadataFactory extends AbstractClassMetadataFactory 
{ 
    /** 
     * @var EntityManagerInterface|null 
     */ 
    private $em; 
 
    /** 
     * @var \Doctrine\DBAL\Platforms\AbstractPlatform 
     */ 
    private $targetPlatform; 
 
    /** 
     * @var MappingDriver 
     */ 
    private $driver; 
 
    /** 
     * @var \Doctrine\Common\EventManager 
     */ 
    private $evm; 
 
    /** 
     * @var array 
     */ 
    private $embeddablesActiveNesting = []; 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function loadMetadata($name) 
    { 
        $loaded = parent::loadMetadata($name); 
 
        array_map([$this, 'resolveDiscriminatorValue'], array_map([$this, 'getMetadataFor'], $loaded)); 
 
        return $loaded; 
    } 
 
    /** 
     * @param EntityManagerInterface $em 
     */ 
    public function setEntityManager(EntityManagerInterface $em) 
    { 
        $this->em = $em; 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function initialize() 
    { 
        $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl(); 
        $this->evm = $this->em->getEventManager(); 
        $this->initialized = true; 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function onNotFoundMetadata($className) 
    { 
        if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) { 
            return; 
        } 
 
        $eventArgs = new OnClassMetadataNotFoundEventArgs($className, $this->em); 
 
        $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs); 
 
        return $eventArgs->getFoundMetadata(); 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) 
    { 
        /* @var $class ClassMetadata */ 
        /* @var $parent ClassMetadata */ 
        if ($parent) { 
            $class->setInheritanceType($parent->inheritanceType); 
            $class->setDiscriminatorColumn($parent->discriminatorColumn); 
            $class->setIdGeneratorType($parent->generatorType); 
            $this->addInheritedFields($class, $parent); 
            $this->addInheritedRelations($class, $parent); 
            $this->addInheritedEmbeddedClasses($class, $parent); 
            $class->setIdentifier($parent->identifier); 
            $class->setVersioned($parent->isVersioned); 
            $class->setVersionField($parent->versionField); 
            $class->setDiscriminatorMap($parent->discriminatorMap); 
            $class->setLifecycleCallbacks($parent->lifecycleCallbacks); 
            $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); 
 
            if ( ! empty($parent->customGeneratorDefinition)) { 
                $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition); 
            } 
 
            if ($parent->isMappedSuperclass) { 
                $class->setCustomRepositoryClass($parent->customRepositoryClassName); 
            } 
        } 
 
        // Invoke driver 
        try { 
            $this->driver->loadMetadataForClass($class->getName(), $class); 
        } catch (ReflectionException $e) { 
            throw MappingException::reflectionFailure($class->getName(), $e); 
        } 
 
        // If this class has a parent the id generator strategy is inherited. 
        // However this is only true if the hierarchy of parents contains the root entity, 
        // if it consists of mapped superclasses these don't necessarily include the id field. 
        if ($parent && $rootEntityFound) { 
            $this->inheritIdGeneratorMapping($class, $parent); 
        } else { 
            $this->completeIdGeneratorMapping($class); 
        } 
 
        if (!$class->isMappedSuperclass) { 
            foreach ($class->embeddedClasses as $property => $embeddableClass) { 
 
                if (isset($embeddableClass['inherited'])) { 
                    continue; 
                } 
 
                if ( ! (isset($embeddableClass['class']) && $embeddableClass['class'])) { 
                    throw MappingException::missingEmbeddedClass($property); 
                } 
 
                if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) { 
                    throw MappingException::infiniteEmbeddableNesting($class->name, $property); 
                } 
 
                $this->embeddablesActiveNesting[$class->name] = true; 
 
                $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); 
 
                if ($embeddableMetadata->isEmbeddedClass) { 
                    $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property); 
                } 
 
                $identifier = $embeddableMetadata->getIdentifier(); 
 
                if (! empty($identifier)) { 
                    $this->inheritIdGeneratorMapping($class, $embeddableMetadata); 
                } 
 
                $class->inlineEmbeddable($property, $embeddableMetadata); 
 
                unset($this->embeddablesActiveNesting[$class->name]); 
            } 
        } 
 
        if ($parent) { 
            if ($parent->isInheritanceTypeSingleTable()) { 
                $class->setPrimaryTable($parent->table); 
            } 
 
            if ($parent) { 
                $this->addInheritedIndexes($class, $parent); 
            } 
 
            if ($parent->cache) { 
                $class->cache = $parent->cache; 
            } 
 
            if ($parent->containsForeignIdentifier) { 
                $class->containsForeignIdentifier = true; 
            } 
 
            if ( ! empty($parent->namedQueries)) { 
                $this->addInheritedNamedQueries($class, $parent); 
            } 
 
            if ( ! empty($parent->namedNativeQueries)) { 
                $this->addInheritedNamedNativeQueries($class, $parent); 
            } 
 
            if ( ! empty($parent->sqlResultSetMappings)) { 
                $this->addInheritedSqlResultSetMappings($class, $parent); 
            } 
 
            if ( ! empty($parent->entityListeners) && empty($class->entityListeners)) { 
                $class->entityListeners = $parent->entityListeners; 
            } 
        } 
 
        $class->setParentClasses($nonSuperclassParents); 
 
        if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) { 
            $this->addDefaultDiscriminatorMap($class); 
        } 
 
        if ($this->evm->hasListeners(Events::loadClassMetadata)) { 
            $eventArgs = new LoadClassMetadataEventArgs($class, $this->em); 
            $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); 
        } 
 
        $this->validateRuntimeMetadata($class, $parent); 
    } 
 
    /** 
     * Validate runtime metadata is correctly defined. 
     * 
     * @param ClassMetadata               $class 
     * @param ClassMetadataInterface|null $parent 
     * 
     * @return void 
     * 
     * @throws MappingException 
     */ 
    protected function validateRuntimeMetadata($class, $parent) 
    { 
        if ( ! $class->reflClass ) { 
            // only validate if there is a reflection class instance 
            return; 
        } 
 
        $class->validateIdentifier(); 
        $class->validateAssociations(); 
        $class->validateLifecycleCallbacks($this->getReflectionService()); 
 
        // verify inheritance 
        if ( ! $class->isMappedSuperclass && !$class->isInheritanceTypeNone()) { 
            if ( ! $parent) { 
                if (count($class->discriminatorMap) == 0) { 
                    throw MappingException::missingDiscriminatorMap($class->name); 
                } 
                if ( ! $class->discriminatorColumn) { 
                    throw MappingException::missingDiscriminatorColumn($class->name); 
                } 
                foreach ($class->subClasses as $subClass) { 
                    if ((new ReflectionClass($subClass))->name !== $subClass) { 
                        throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name); 
                    } 
                } 
            } 
        } else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) { 
            // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy 
            throw MappingException::noInheritanceOnMappedSuperClass($class->name); 
        } 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function newClassMetadataInstance($className) 
    { 
        return new ClassMetadata($className, $this->em->getConfiguration()->getNamingStrategy()); 
    } 
 
    /** 
     * 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 
     */ 
    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); 
    } 
 
    /** 
     * Adds a default discriminator map if no one is given 
     * 
     * If an entity is of any inheritance type and does not contain a 
     * discriminator map, then the map is generated automatically. This process 
     * is expensive computation wise. 
     * 
     * The automatically generated discriminator map contains the lowercase short name of 
     * each class as key. 
     * 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class 
     * 
     * @throws MappingException 
     */ 
    private function addDefaultDiscriminatorMap(ClassMetadata $class) 
    { 
        $allClasses = $this->driver->getAllClassNames(); 
        $fqcn = $class->getName(); 
        $map = [$this->getShortName($class->name) => $fqcn]; 
 
        $duplicates = []; 
        foreach ($allClasses as $subClassCandidate) { 
            if (is_subclass_of($subClassCandidate, $fqcn)) { 
                $shortName = $this->getShortName($subClassCandidate); 
 
                if (isset($map[$shortName])) { 
                    $duplicates[] = $shortName; 
                } 
 
                $map[$shortName] = $subClassCandidate; 
            } 
        } 
 
        if ($duplicates) { 
            throw MappingException::duplicateDiscriminatorEntry($class->name, $duplicates, $map); 
        } 
 
        $class->setDiscriminatorMap($map); 
    } 
 
    /** 
     * Gets the lower-case short name of a class. 
     * 
     * @param string $className 
     * 
     * @return string 
     */ 
    private function getShortName($className) 
    { 
        if (strpos($className, "\\") === false) { 
            return strtolower($className); 
        } 
 
        $parts = explode("\\", $className); 
 
        return strtolower(end($parts)); 
    } 
 
    /** 
     * Adds inherited fields to the subclass mapping. 
     * 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass 
     * 
     * @return void 
     */ 
    private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass) 
    { 
        foreach ($parentClass->fieldMappings as $mapping) { 
            if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { 
                $mapping['inherited'] = $parentClass->name; 
            } 
            if (! isset($mapping['declared'])) { 
                $mapping['declared'] = $parentClass->name; 
            } 
            $subClass->addInheritedFieldMapping($mapping); 
        } 
        foreach ($parentClass->reflFields as $name => $field) { 
            $subClass->reflFields[$name] = $field; 
        } 
    } 
 
    /** 
     * Adds inherited association mappings to the subclass mapping. 
     * 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass 
     * 
     * @return void 
     * 
     * @throws MappingException 
     */ 
    private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass) 
    { 
        foreach ($parentClass->associationMappings as $field => $mapping) { 
            if ($parentClass->isMappedSuperclass) { 
                if ($mapping['type'] & ClassMetadata::TO_MANY && !$mapping['isOwningSide']) { 
                    throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name, $field); 
                } 
                $mapping['sourceEntity'] = $subClass->name; 
            } 
 
            //$subclassMapping = $mapping; 
            if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { 
                $mapping['inherited'] = $parentClass->name; 
            } 
            if ( ! isset($mapping['declared'])) { 
                $mapping['declared'] = $parentClass->name; 
            } 
            $subClass->addInheritedAssociationMapping($mapping); 
        } 
    } 
 
    private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass) 
    { 
        foreach ($parentClass->embeddedClasses as $field => $embeddedClass) { 
            if ( ! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) { 
                $embeddedClass['inherited'] = $parentClass->name; 
            } 
            if ( ! isset($embeddedClass['declared'])) { 
                $embeddedClass['declared'] = $parentClass->name; 
            } 
 
            $subClass->embeddedClasses[$field] = $embeddedClass; 
        } 
    } 
 
    /** 
     * Adds nested embedded classes metadata to a parent class. 
     * 
     * @param ClassMetadata $subClass    Sub embedded class metadata to add nested embedded classes metadata from. 
     * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to. 
     * @param string        $prefix      Embedded classes' prefix to use for nested embedded classes field names. 
     */ 
    private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix) 
    { 
        foreach ($subClass->embeddedClasses as $property => $embeddableClass) { 
            if (isset($embeddableClass['inherited'])) { 
                continue; 
            } 
 
            $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); 
 
            $parentClass->mapEmbedded( 
                [ 
                    'fieldName' => $prefix . '.' . $property, 
                    'class' => $embeddableMetadata->name, 
                    'columnPrefix' => $embeddableClass['columnPrefix'], 
                    'declaredField' => $embeddableClass['declaredField'] 
                            ? $prefix . '.' . $embeddableClass['declaredField'] 
                            : $prefix, 
                    'originalField' => $embeddableClass['originalField'] ?: $property, 
                ] 
            ); 
        } 
    } 
 
    /** 
     * Copy the table indices from the parent class superclass to the child class 
     * 
     * @param ClassMetadata $subClass 
     * @param ClassMetadata $parentClass 
     * 
     * @return void 
     */ 
    private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass) 
    { 
        if (! $parentClass->isMappedSuperclass) { 
            return; 
        } 
 
        foreach (['uniqueConstraints', 'indexes'] as $indexType) { 
            if (isset($parentClass->table[$indexType])) { 
                foreach ($parentClass->table[$indexType] as $indexName => $index) { 
                    if (isset($subClass->table[$indexType][$indexName])) { 
                        continue; // Let the inheriting table override indices 
                    } 
 
                    $subClass->table[$indexType][$indexName] = $index; 
                } 
            } 
        } 
    } 
 
    /** 
     * Adds inherited named queries to the subclass mapping. 
     * 
     * @since 2.2 
     * 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass 
     * 
     * @return void 
     */ 
    private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass) 
    { 
        foreach ($parentClass->namedQueries as $name => $query) { 
            if ( ! isset ($subClass->namedQueries[$name])) { 
                $subClass->addNamedQuery( 
                    [ 
                        'name'  => $query['name'], 
                        'query' => $query['query'] 
                    ] 
                ); 
            } 
        } 
    } 
 
    /** 
     * Adds inherited named native queries to the subclass mapping. 
     * 
     * @since 2.3 
     * 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass 
     * 
     * @return void 
     */ 
    private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass) 
    { 
        foreach ($parentClass->namedNativeQueries as $name => $query) { 
            if ( ! isset ($subClass->namedNativeQueries[$name])) { 
                $subClass->addNamedNativeQuery( 
                    [ 
                        'name'              => $query['name'], 
                        'query'             => $query['query'], 
                        'isSelfClass'       => $query['isSelfClass'], 
                        'resultSetMapping'  => $query['resultSetMapping'], 
                        'resultClass'       => $query['isSelfClass'] ? $subClass->name : $query['resultClass'], 
                    ] 
                ); 
            } 
        } 
    } 
 
    /** 
     * Adds inherited sql result set mappings to the subclass mapping. 
     * 
     * @since 2.3 
     * 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass 
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass 
     * 
     * @return void 
     */ 
    private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass) 
    { 
        foreach ($parentClass->sqlResultSetMappings as $name => $mapping) { 
            if ( ! isset ($subClass->sqlResultSetMappings[$name])) { 
                $entities = []; 
                foreach ($mapping['entities'] as $entity) { 
                    $entities[] = [ 
                        'fields'                => $entity['fields'], 
                        'isSelfClass'           => $entity['isSelfClass'], 
                        'discriminatorColumn'   => $entity['discriminatorColumn'], 
                        'entityClass'           => $entity['isSelfClass'] ? $subClass->name : $entity['entityClass'], 
                    ]; 
                } 
 
                $subClass->addSqlResultSetMapping( 
                    [ 
                        'name'          => $mapping['name'], 
                        'columns'       => $mapping['columns'], 
                        'entities'      => $entities, 
                    ] 
                ); 
            } 
        } 
    } 
 
    /** 
     * Completes the ID generator mapping. If "auto" is specified we choose the generator 
     * most appropriate for the targeted database platform. 
     * 
     * @param ClassMetadataInfo $class 
     * 
     * @return void 
     * 
     * @throws ORMException 
     */ 
    private function completeIdGeneratorMapping(ClassMetadataInfo $class) 
    { 
        $idGenType = $class->generatorType; 
        if ($idGenType == ClassMetadata::GENERATOR_TYPE_AUTO) { 
            if ($this->getTargetPlatform()->prefersSequences()) { 
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE); 
            } else if ($this->getTargetPlatform()->prefersIdentityColumns()) { 
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY); 
            } else { 
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_TABLE); 
            } 
        } 
 
        // Create & assign an appropriate ID generator instance 
        switch ($class->generatorType) { 
            case ClassMetadata::GENERATOR_TYPE_IDENTITY: 
                $sequenceName = null; 
                $fieldName    = $class->identifier ? $class->getSingleIdentifierFieldName() : null; 
 
                // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour. 
                if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) { 
                    $columnName     = $class->getSingleIdentifierColumnName(); 
                    $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); 
                    $sequencePrefix = $class->getSequencePrefix($this->getTargetPlatform()); 
                    $sequenceName   = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName); 
                    $definition     = [ 
                        'sequenceName' => $this->getTargetPlatform()->fixSchemaElementName($sequenceName) 
                    ]; 
 
                    if ($quoted) { 
                        $definition['quoted'] = true; 
                    } 
 
                    $sequenceName = $this 
                        ->em 
                        ->getConfiguration() 
                        ->getQuoteStrategy() 
                        ->getSequenceName($definition, $class, $this->getTargetPlatform()); 
                } 
 
                $generator = ($fieldName && $class->fieldMappings[$fieldName]['type'] === 'bigint') 
                    ? new BigIntegerIdentityGenerator($sequenceName) 
                    : new IdentityGenerator($sequenceName); 
 
                $class->setIdGenerator($generator); 
 
                break; 
 
            case ClassMetadata::GENERATOR_TYPE_SEQUENCE: 
                // If there is no sequence definition yet, create a default definition 
                $definition = $class->sequenceGeneratorDefinition; 
 
                if ( ! $definition) { 
                    $fieldName      = $class->getSingleIdentifierFieldName(); 
                    $sequenceName   = $class->getSequenceName($this->getTargetPlatform()); 
                    $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); 
 
                    $definition = [ 
                        'sequenceName'      => $this->getTargetPlatform()->fixSchemaElementName($sequenceName), 
                        'allocationSize'    => 1, 
                        'initialValue'      => 1, 
                    ]; 
 
                    if ($quoted) { 
                        $definition['quoted'] = true; 
                    } 
 
                    $class->setSequenceGeneratorDefinition($definition); 
                } 
 
                $sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator( 
                    $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->getTargetPlatform()), 
                    $definition['allocationSize'] 
                ); 
                $class->setIdGenerator($sequenceGenerator); 
                break; 
 
            case ClassMetadata::GENERATOR_TYPE_NONE: 
                $class->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator()); 
                break; 
 
            case ClassMetadata::GENERATOR_TYPE_UUID: 
                $class->setIdGenerator(new \Doctrine\ORM\Id\UuidGenerator()); 
                break; 
 
            case ClassMetadata::GENERATOR_TYPE_TABLE: 
                throw new ORMException("TableGenerator not yet implemented."); 
                break; 
 
            case ClassMetadata::GENERATOR_TYPE_CUSTOM: 
                $definition = $class->customGeneratorDefinition; 
                if ($definition === null) { 
                    throw new ORMException("Can't instantiate custom generator : no custom generator definition"); 
                } 
                if ( ! class_exists($definition['class'])) { 
                    throw new ORMException("Can't instantiate custom generator : " . 
                        $definition['class']); 
                } 
                $class->setIdGenerator(new $definition['class']); 
                break; 
 
            default: 
                throw new ORMException("Unknown generator type: " . $class->generatorType); 
        } 
    } 
 
    /** 
     * Inherits the ID generator mapping from a parent class. 
     * 
     * @param ClassMetadataInfo $class 
     * @param ClassMetadataInfo $parent 
     */ 
    private function inheritIdGeneratorMapping(ClassMetadataInfo $class, ClassMetadataInfo $parent) 
    { 
        if ($parent->isIdGeneratorSequence()) { 
            $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition); 
        } elseif ($parent->isIdGeneratorTable()) { 
            $class->tableGeneratorDefinition = $parent->tableGeneratorDefinition; 
        } 
 
        if ($parent->generatorType) { 
            $class->setIdGeneratorType($parent->generatorType); 
        } 
 
        if ($parent->idGenerator) { 
            $class->setIdGenerator($parent->idGenerator); 
        } 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService) 
    { 
        /* @var $class ClassMetadata */ 
        $class->wakeupReflection($reflService); 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService) 
    { 
        /* @var $class ClassMetadata */ 
        $class->initializeReflection($reflService); 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) 
    { 
        return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName; 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function getDriver() 
    { 
        return $this->driver; 
    } 
 
    /** 
     * {@inheritDoc} 
     */ 
    protected function isEntity(ClassMetadataInterface $class) 
    { 
        return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false; 
    } 
 
    /** 
     * @return Platforms\AbstractPlatform 
     */ 
    private function getTargetPlatform() 
    { 
        if (!$this->targetPlatform) { 
            $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform(); 
        } 
 
        return $this->targetPlatform; 
    } 
} 
 
interface_exists(ClassMetadataInterface::class); 
interface_exists(ReflectionService::class);