vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php line 310

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ORM\Mapping;
  4. use Doctrine\Common\EventManager;
  5. use Doctrine\DBAL\Platforms;
  6. use Doctrine\DBAL\Platforms\AbstractPlatform;
  7. use Doctrine\Deprecations\Deprecation;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
  10. use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
  11. use Doctrine\ORM\Events;
  12. use Doctrine\ORM\Exception\ORMException;
  13. use Doctrine\ORM\Id\AssignedGenerator;
  14. use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
  15. use Doctrine\ORM\Id\IdentityGenerator;
  16. use Doctrine\ORM\Id\SequenceGenerator;
  17. use Doctrine\ORM\Id\UuidGenerator;
  18. use Doctrine\ORM\Mapping\Exception\CannotGenerateIds;
  19. use Doctrine\ORM\Mapping\Exception\InvalidCustomGenerator;
  20. use Doctrine\ORM\Mapping\Exception\UnknownGeneratorType;
  21. use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
  22. use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
  23. use Doctrine\Persistence\Mapping\Driver\MappingDriver;
  24. use Doctrine\Persistence\Mapping\ReflectionService;
  25. use ReflectionClass;
  26. use ReflectionException;
  27. use function assert;
  28. use function class_exists;
  29. use function count;
  30. use function end;
  31. use function explode;
  32. use function in_array;
  33. use function is_subclass_of;
  34. use function strlen;
  35. use function strpos;
  36. use function strtolower;
  37. use function substr;
  38. /**
  39.  * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
  40.  * metadata mapping information of a class which describes how a class should be mapped
  41.  * to a relational database.
  42.  *
  43.  * @extends AbstractClassMetadataFactory<ClassMetadata>
  44.  */
  45. class ClassMetadataFactory extends AbstractClassMetadataFactory
  46. {
  47.     /** @var EntityManagerInterface|null */
  48.     private $em;
  49.     /** @var AbstractPlatform|null */
  50.     private $targetPlatform;
  51.     /** @var MappingDriver */
  52.     private $driver;
  53.     /** @var EventManager */
  54.     private $evm;
  55.     /** @var mixed[] */
  56.     private $embeddablesActiveNesting = [];
  57.     /**
  58.      * @return void
  59.      */
  60.     public function setEntityManager(EntityManagerInterface $em)
  61.     {
  62.         $this->em $em;
  63.     }
  64.     /**
  65.      * {@inheritDoc}
  66.      */
  67.     protected function initialize()
  68.     {
  69.         $this->driver      $this->em->getConfiguration()->getMetadataDriverImpl();
  70.         $this->evm         $this->em->getEventManager();
  71.         $this->initialized true;
  72.     }
  73.     /**
  74.      * {@inheritDoc}
  75.      */
  76.     protected function onNotFoundMetadata($className)
  77.     {
  78.         if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) {
  79.             return null;
  80.         }
  81.         $eventArgs = new OnClassMetadataNotFoundEventArgs($className$this->em);
  82.         $this->evm->dispatchEvent(Events::onClassMetadataNotFound$eventArgs);
  83.         $classMetadata $eventArgs->getFoundMetadata();
  84.         assert($classMetadata instanceof ClassMetadata || $classMetadata === null);
  85.         return $classMetadata;
  86.     }
  87.     /**
  88.      * {@inheritDoc}
  89.      */
  90.     protected function doLoadMetadata($class$parent$rootEntityFound, array $nonSuperclassParents)
  91.     {
  92.         if ($parent) {
  93.             $class->setInheritanceType($parent->inheritanceType);
  94.             $class->setDiscriminatorColumn($parent->discriminatorColumn);
  95.             $class->setIdGeneratorType($parent->generatorType);
  96.             $this->addInheritedFields($class$parent);
  97.             $this->addInheritedRelations($class$parent);
  98.             $this->addInheritedEmbeddedClasses($class$parent);
  99.             $class->setIdentifier($parent->identifier);
  100.             $class->setVersioned($parent->isVersioned);
  101.             $class->setVersionField($parent->versionField);
  102.             $class->setDiscriminatorMap($parent->discriminatorMap);
  103.             $class->setLifecycleCallbacks($parent->lifecycleCallbacks);
  104.             $class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
  105.             if (! empty($parent->customGeneratorDefinition)) {
  106.                 $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition);
  107.             }
  108.             if ($parent->isMappedSuperclass) {
  109.                 $class->setCustomRepositoryClass($parent->customRepositoryClassName);
  110.             }
  111.         }
  112.         // Invoke driver
  113.         try {
  114.             $this->driver->loadMetadataForClass($class->getName(), $class);
  115.         } catch (ReflectionException $e) {
  116.             throw MappingException::reflectionFailure($class->getName(), $e);
  117.         }
  118.         // If this class has a parent the id generator strategy is inherited.
  119.         // However this is only true if the hierarchy of parents contains the root entity,
  120.         // if it consists of mapped superclasses these don't necessarily include the id field.
  121.         if ($parent && $rootEntityFound) {
  122.             $this->inheritIdGeneratorMapping($class$parent);
  123.         } else {
  124.             $this->completeIdGeneratorMapping($class);
  125.         }
  126.         if (! $class->isMappedSuperclass) {
  127.             foreach ($class->embeddedClasses as $property => $embeddableClass) {
  128.                 if (isset($embeddableClass['inherited'])) {
  129.                     continue;
  130.                 }
  131.                 if (! (isset($embeddableClass['class']) && $embeddableClass['class'])) {
  132.                     throw MappingException::missingEmbeddedClass($property);
  133.                 }
  134.                 if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) {
  135.                     throw MappingException::infiniteEmbeddableNesting($class->name$property);
  136.                 }
  137.                 $this->embeddablesActiveNesting[$class->name] = true;
  138.                 $embeddableMetadata $this->getMetadataFor($embeddableClass['class']);
  139.                 if ($embeddableMetadata->isEmbeddedClass) {
  140.                     $this->addNestedEmbeddedClasses($embeddableMetadata$class$property);
  141.                 }
  142.                 $identifier $embeddableMetadata->getIdentifier();
  143.                 if (! empty($identifier)) {
  144.                     $this->inheritIdGeneratorMapping($class$embeddableMetadata);
  145.                 }
  146.                 $class->inlineEmbeddable($property$embeddableMetadata);
  147.                 unset($this->embeddablesActiveNesting[$class->name]);
  148.             }
  149.         }
  150.         if ($parent) {
  151.             if ($parent->isInheritanceTypeSingleTable()) {
  152.                 $class->setPrimaryTable($parent->table);
  153.             }
  154.             $this->addInheritedIndexes($class$parent);
  155.             if ($parent->cache) {
  156.                 $class->cache $parent->cache;
  157.             }
  158.             if ($parent->containsForeignIdentifier) {
  159.                 $class->containsForeignIdentifier true;
  160.             }
  161.             if (! empty($parent->namedQueries)) {
  162.                 $this->addInheritedNamedQueries($class$parent);
  163.             }
  164.             if (! empty($parent->namedNativeQueries)) {
  165.                 $this->addInheritedNamedNativeQueries($class$parent);
  166.             }
  167.             if (! empty($parent->sqlResultSetMappings)) {
  168.                 $this->addInheritedSqlResultSetMappings($class$parent);
  169.             }
  170.             if (! empty($parent->entityListeners) && empty($class->entityListeners)) {
  171.                 $class->entityListeners $parent->entityListeners;
  172.             }
  173.         }
  174.         $class->setParentClasses($nonSuperclassParents);
  175.         if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) {
  176.             $this->addDefaultDiscriminatorMap($class);
  177.         }
  178.         if ($this->evm->hasListeners(Events::loadClassMetadata)) {
  179.             $eventArgs = new LoadClassMetadataEventArgs($class$this->em);
  180.             $this->evm->dispatchEvent(Events::loadClassMetadata$eventArgs);
  181.         }
  182.         if ($class->changeTrackingPolicy === ClassMetadataInfo::CHANGETRACKING_NOTIFY) {
  183.             Deprecation::trigger(
  184.                 'doctrine/orm',
  185.                 'https://github.com/doctrine/orm/issues/8383',
  186.                 'NOTIFY Change Tracking policy used in "%s" is deprecated, use deferred explicit instead.',
  187.                 $class->name
  188.             );
  189.         }
  190.         $this->validateRuntimeMetadata($class$parent);
  191.     }
  192.     /**
  193.      * Validate runtime metadata is correctly defined.
  194.      *
  195.      * @param ClassMetadata               $class
  196.      * @param ClassMetadataInterface|null $parent
  197.      *
  198.      * @return void
  199.      *
  200.      * @throws MappingException
  201.      */
  202.     protected function validateRuntimeMetadata($class$parent)
  203.     {
  204.         if (! $class->reflClass) {
  205.             // only validate if there is a reflection class instance
  206.             return;
  207.         }
  208.         $class->validateIdentifier();
  209.         $class->validateAssociations();
  210.         $class->validateLifecycleCallbacks($this->getReflectionService());
  211.         // verify inheritance
  212.         if (! $class->isMappedSuperclass && ! $class->isInheritanceTypeNone()) {
  213.             if (! $parent) {
  214.                 if (count($class->discriminatorMap) === 0) {
  215.                     throw MappingException::missingDiscriminatorMap($class->name);
  216.                 }
  217.                 if (! $class->discriminatorColumn) {
  218.                     throw MappingException::missingDiscriminatorColumn($class->name);
  219.                 }
  220.                 foreach ($class->subClasses as $subClass) {
  221.                     if ((new ReflectionClass($subClass))->name !== $subClass) {
  222.                         throw MappingException::invalidClassInDiscriminatorMap($subClass$class->name);
  223.                     }
  224.                 }
  225.             } else {
  226.                 assert($parent instanceof ClassMetadataInfo); // https://github.com/doctrine/orm/issues/8746
  227.                 if (
  228.                     ! $class->reflClass->isAbstract()
  229.                     && ! in_array($class->name$class->discriminatorMaptrue)
  230.                 ) {
  231.                     throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name$class->rootEntityName);
  232.                 }
  233.             }
  234.         } elseif ($class->isMappedSuperclass && $class->name === $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
  235.             // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
  236.             throw MappingException::noInheritanceOnMappedSuperClass($class->name);
  237.         }
  238.     }
  239.     /**
  240.      * {@inheritDoc}
  241.      */
  242.     protected function newClassMetadataInstance($className)
  243.     {
  244.         return new ClassMetadata($className$this->em->getConfiguration()->getNamingStrategy());
  245.     }
  246.     /**
  247.      * Adds a default discriminator map if no one is given
  248.      *
  249.      * If an entity is of any inheritance type and does not contain a
  250.      * discriminator map, then the map is generated automatically. This process
  251.      * is expensive computation wise.
  252.      *
  253.      * The automatically generated discriminator map contains the lowercase short name of
  254.      * each class as key.
  255.      *
  256.      * @throws MappingException
  257.      */
  258.     private function addDefaultDiscriminatorMap(ClassMetadata $class): void
  259.     {
  260.         $allClasses $this->driver->getAllClassNames();
  261.         $fqcn       $class->getName();
  262.         $map        = [$this->getShortName($class->name) => $fqcn];
  263.         $duplicates = [];
  264.         foreach ($allClasses as $subClassCandidate) {
  265.             if (is_subclass_of($subClassCandidate$fqcn)) {
  266.                 $shortName $this->getShortName($subClassCandidate);
  267.                 if (isset($map[$shortName])) {
  268.                     $duplicates[] = $shortName;
  269.                 }
  270.                 $map[$shortName] = $subClassCandidate;
  271.             }
  272.         }
  273.         if ($duplicates) {
  274.             throw MappingException::duplicateDiscriminatorEntry($class->name$duplicates$map);
  275.         }
  276.         $class->setDiscriminatorMap($map);
  277.     }
  278.     /**
  279.      * Gets the lower-case short name of a class.
  280.      *
  281.      * @psalm-param class-string $className
  282.      */
  283.     private function getShortName(string $className): string
  284.     {
  285.         if (strpos($className'\\') === false) {
  286.             return strtolower($className);
  287.         }
  288.         $parts explode('\\'$className);
  289.         return strtolower(end($parts));
  290.     }
  291.     /**
  292.      * Adds inherited fields to the subclass mapping.
  293.      */
  294.     private function addInheritedFields(ClassMetadata $subClassClassMetadata $parentClass): void
  295.     {
  296.         foreach ($parentClass->fieldMappings as $mapping) {
  297.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  298.                 $mapping['inherited'] = $parentClass->name;
  299.             }
  300.             if (! isset($mapping['declared'])) {
  301.                 $mapping['declared'] = $parentClass->name;
  302.             }
  303.             $subClass->addInheritedFieldMapping($mapping);
  304.         }
  305.         foreach ($parentClass->reflFields as $name => $field) {
  306.             $subClass->reflFields[$name] = $field;
  307.         }
  308.     }
  309.     /**
  310.      * Adds inherited association mappings to the subclass mapping.
  311.      *
  312.      * @throws MappingException
  313.      */
  314.     private function addInheritedRelations(ClassMetadata $subClassClassMetadata $parentClass): void
  315.     {
  316.         foreach ($parentClass->associationMappings as $field => $mapping) {
  317.             if ($parentClass->isMappedSuperclass) {
  318.                 if ($mapping['type'] & ClassMetadata::TO_MANY && ! $mapping['isOwningSide']) {
  319.                     throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name$field);
  320.                 }
  321.                 $mapping['sourceEntity'] = $subClass->name;
  322.             }
  323.             //$subclassMapping = $mapping;
  324.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  325.                 $mapping['inherited'] = $parentClass->name;
  326.             }
  327.             if (! isset($mapping['declared'])) {
  328.                 $mapping['declared'] = $parentClass->name;
  329.             }
  330.             $subClass->addInheritedAssociationMapping($mapping);
  331.         }
  332.     }
  333.     private function addInheritedEmbeddedClasses(ClassMetadata $subClassClassMetadata $parentClass): void
  334.     {
  335.         foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
  336.             if (! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) {
  337.                 $embeddedClass['inherited'] = $parentClass->name;
  338.             }
  339.             if (! isset($embeddedClass['declared'])) {
  340.                 $embeddedClass['declared'] = $parentClass->name;
  341.             }
  342.             $subClass->embeddedClasses[$field] = $embeddedClass;
  343.         }
  344.     }
  345.     /**
  346.      * Adds nested embedded classes metadata to a parent class.
  347.      *
  348.      * @param ClassMetadata $subClass    Sub embedded class metadata to add nested embedded classes metadata from.
  349.      * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to.
  350.      * @param string        $prefix      Embedded classes' prefix to use for nested embedded classes field names.
  351.      */
  352.     private function addNestedEmbeddedClasses(
  353.         ClassMetadata $subClass,
  354.         ClassMetadata $parentClass,
  355.         string $prefix
  356.     ): void {
  357.         foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
  358.             if (isset($embeddableClass['inherited'])) {
  359.                 continue;
  360.             }
  361.             $embeddableMetadata $this->getMetadataFor($embeddableClass['class']);
  362.             $parentClass->mapEmbedded(
  363.                 [
  364.                     'fieldName' => $prefix '.' $property,
  365.                     'class' => $embeddableMetadata->name,
  366.                     'columnPrefix' => $embeddableClass['columnPrefix'],
  367.                     'declaredField' => $embeddableClass['declaredField']
  368.                             ? $prefix '.' $embeddableClass['declaredField']
  369.                             : $prefix,
  370.                     'originalField' => $embeddableClass['originalField'] ?: $property,
  371.                 ]
  372.             );
  373.         }
  374.     }
  375.     /**
  376.      * Copy the table indices from the parent class superclass to the child class
  377.      */
  378.     private function addInheritedIndexes(ClassMetadata $subClassClassMetadata $parentClass): void
  379.     {
  380.         if (! $parentClass->isMappedSuperclass) {
  381.             return;
  382.         }
  383.         foreach (['uniqueConstraints''indexes'] as $indexType) {
  384.             if (isset($parentClass->table[$indexType])) {
  385.                 foreach ($parentClass->table[$indexType] as $indexName => $index) {
  386.                     if (isset($subClass->table[$indexType][$indexName])) {
  387.                         continue; // Let the inheriting table override indices
  388.                     }
  389.                     $subClass->table[$indexType][$indexName] = $index;
  390.                 }
  391.             }
  392.         }
  393.     }
  394.     /**
  395.      * Adds inherited named queries to the subclass mapping.
  396.      */
  397.     private function addInheritedNamedQueries(ClassMetadata $subClassClassMetadata $parentClass): void
  398.     {
  399.         foreach ($parentClass->namedQueries as $name => $query) {
  400.             if (! isset($subClass->namedQueries[$name])) {
  401.                 $subClass->addNamedQuery(
  402.                     [
  403.                         'name'  => $query['name'],
  404.                         'query' => $query['query'],
  405.                     ]
  406.                 );
  407.             }
  408.         }
  409.     }
  410.     /**
  411.      * Adds inherited named native queries to the subclass mapping.
  412.      */
  413.     private function addInheritedNamedNativeQueries(ClassMetadata $subClassClassMetadata $parentClass): void
  414.     {
  415.         foreach ($parentClass->namedNativeQueries as $name => $query) {
  416.             if (! isset($subClass->namedNativeQueries[$name])) {
  417.                 $subClass->addNamedNativeQuery(
  418.                     [
  419.                         'name'              => $query['name'],
  420.                         'query'             => $query['query'],
  421.                         'isSelfClass'       => $query['isSelfClass'],
  422.                         'resultSetMapping'  => $query['resultSetMapping'],
  423.                         'resultClass'       => $query['isSelfClass'] ? $subClass->name $query['resultClass'],
  424.                     ]
  425.                 );
  426.             }
  427.         }
  428.     }
  429.     /**
  430.      * Adds inherited sql result set mappings to the subclass mapping.
  431.      */
  432.     private function addInheritedSqlResultSetMappings(ClassMetadata $subClassClassMetadata $parentClass): void
  433.     {
  434.         foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
  435.             if (! isset($subClass->sqlResultSetMappings[$name])) {
  436.                 $entities = [];
  437.                 foreach ($mapping['entities'] as $entity) {
  438.                     $entities[] = [
  439.                         'fields'                => $entity['fields'],
  440.                         'isSelfClass'           => $entity['isSelfClass'],
  441.                         'discriminatorColumn'   => $entity['discriminatorColumn'],
  442.                         'entityClass'           => $entity['isSelfClass'] ? $subClass->name $entity['entityClass'],
  443.                     ];
  444.                 }
  445.                 $subClass->addSqlResultSetMapping(
  446.                     [
  447.                         'name'          => $mapping['name'],
  448.                         'columns'       => $mapping['columns'],
  449.                         'entities'      => $entities,
  450.                     ]
  451.                 );
  452.             }
  453.         }
  454.     }
  455.     /**
  456.      * Completes the ID generator mapping. If "auto" is specified we choose the generator
  457.      * most appropriate for the targeted database platform.
  458.      *
  459.      * @throws ORMException
  460.      */
  461.     private function completeIdGeneratorMapping(ClassMetadataInfo $class): void
  462.     {
  463.         $idGenType $class->generatorType;
  464.         if ($idGenType === ClassMetadata::GENERATOR_TYPE_AUTO) {
  465.             $class->setIdGeneratorType($this->determineIdGeneratorStrategy($this->getTargetPlatform()));
  466.         }
  467.         // Create & assign an appropriate ID generator instance
  468.         switch ($class->generatorType) {
  469.             case ClassMetadata::GENERATOR_TYPE_IDENTITY:
  470.                 $sequenceName null;
  471.                 $fieldName    $class->identifier $class->getSingleIdentifierFieldName() : null;
  472.                 // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
  473.                 if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
  474.                     $columnName     $class->getSingleIdentifierColumnName();
  475.                     $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
  476.                     $sequencePrefix $class->getSequencePrefix($this->getTargetPlatform());
  477.                     $sequenceName   $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix$columnName);
  478.                     $definition     = [
  479.                         'sequenceName' => $this->truncateSequenceName($sequenceName),
  480.                     ];
  481.                     if ($quoted) {
  482.                         $definition['quoted'] = true;
  483.                     }
  484.                     $sequenceName $this
  485.                         ->em
  486.                         ->getConfiguration()
  487.                         ->getQuoteStrategy()
  488.                         ->getSequenceName($definition$class$this->getTargetPlatform());
  489.                 }
  490.                 $generator $fieldName && $class->fieldMappings[$fieldName]['type'] === 'bigint'
  491.                     ? new BigIntegerIdentityGenerator($sequenceName)
  492.                     : new IdentityGenerator($sequenceName);
  493.                 $class->setIdGenerator($generator);
  494.                 break;
  495.             case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
  496.                 // If there is no sequence definition yet, create a default definition
  497.                 $definition $class->sequenceGeneratorDefinition;
  498.                 if (! $definition) {
  499.                     $fieldName    $class->getSingleIdentifierFieldName();
  500.                     $sequenceName $class->getSequenceName($this->getTargetPlatform());
  501.                     $quoted       = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
  502.                     $definition = [
  503.                         'sequenceName'      => $this->truncateSequenceName($sequenceName),
  504.                         'allocationSize'    => 1,
  505.                         'initialValue'      => 1,
  506.                     ];
  507.                     if ($quoted) {
  508.                         $definition['quoted'] = true;
  509.                     }
  510.                     $class->setSequenceGeneratorDefinition($definition);
  511.                 }
  512.                 $sequenceGenerator = new SequenceGenerator(
  513.                     $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition$class$this->getTargetPlatform()),
  514.                     (int) $definition['allocationSize']
  515.                 );
  516.                 $class->setIdGenerator($sequenceGenerator);
  517.                 break;
  518.             case ClassMetadata::GENERATOR_TYPE_NONE:
  519.                 $class->setIdGenerator(new AssignedGenerator());
  520.                 break;
  521.             case ClassMetadata::GENERATOR_TYPE_UUID:
  522.                 Deprecation::trigger(
  523.                     'doctrine/orm',
  524.                     'https://github.com/doctrine/orm/issues/7312',
  525.                     'Mapping for %s: the "UUID" id generator strategy is deprecated with no replacement',
  526.                     $class->name
  527.                 );
  528.                 $class->setIdGenerator(new UuidGenerator());
  529.                 break;
  530.             case ClassMetadata::GENERATOR_TYPE_CUSTOM:
  531.                 $definition $class->customGeneratorDefinition;
  532.                 if ($definition === null) {
  533.                     throw InvalidCustomGenerator::onClassNotConfigured();
  534.                 }
  535.                 if (! class_exists($definition['class'])) {
  536.                     throw InvalidCustomGenerator::onMissingClass($definition);
  537.                 }
  538.                 $class->setIdGenerator(new $definition['class']());
  539.                 break;
  540.             default:
  541.                 throw UnknownGeneratorType::create($class->generatorType);
  542.         }
  543.     }
  544.     /**
  545.      * @psalm-return ClassMetadata::GENERATOR_TYPE_SEQUENCE|ClassMetadata::GENERATOR_TYPE_IDENTITY
  546.      */
  547.     private function determineIdGeneratorStrategy(AbstractPlatform $platform): int
  548.     {
  549.         if (
  550.             $platform instanceof Platforms\OraclePlatform
  551.             || $platform instanceof Platforms\PostgreSQLPlatform
  552.         ) {
  553.             return ClassMetadata::GENERATOR_TYPE_SEQUENCE;
  554.         }
  555.         if ($platform->supportsIdentityColumns()) {
  556.             return ClassMetadata::GENERATOR_TYPE_IDENTITY;
  557.         }
  558.         if ($platform->supportsSequences()) {
  559.             return ClassMetadata::GENERATOR_TYPE_SEQUENCE;
  560.         }
  561.         throw CannotGenerateIds::withPlatform($platform);
  562.     }
  563.     private function truncateSequenceName(string $schemaElementName): string
  564.     {
  565.         $platform $this->getTargetPlatform();
  566.         if (! $platform instanceof Platforms\OraclePlatform && ! $platform instanceof Platforms\SQLAnywherePlatform) {
  567.             return $schemaElementName;
  568.         }
  569.         $maxIdentifierLength $platform->getMaxIdentifierLength();
  570.         if (strlen($schemaElementName) > $maxIdentifierLength) {
  571.             return substr($schemaElementName0$maxIdentifierLength);
  572.         }
  573.         return $schemaElementName;
  574.     }
  575.     /**
  576.      * Inherits the ID generator mapping from a parent class.
  577.      */
  578.     private function inheritIdGeneratorMapping(ClassMetadataInfo $classClassMetadataInfo $parent): void
  579.     {
  580.         if ($parent->isIdGeneratorSequence()) {
  581.             $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
  582.         }
  583.         if ($parent->generatorType) {
  584.             $class->setIdGeneratorType($parent->generatorType);
  585.         }
  586.         if ($parent->idGenerator) {
  587.             $class->setIdGenerator($parent->idGenerator);
  588.         }
  589.     }
  590.     /**
  591.      * {@inheritDoc}
  592.      */
  593.     protected function wakeupReflection(ClassMetadataInterface $classReflectionService $reflService)
  594.     {
  595.         assert($class instanceof ClassMetadata);
  596.         $class->wakeupReflection($reflService);
  597.     }
  598.     /**
  599.      * {@inheritDoc}
  600.      */
  601.     protected function initializeReflection(ClassMetadataInterface $classReflectionService $reflService)
  602.     {
  603.         assert($class instanceof ClassMetadata);
  604.         $class->initializeReflection($reflService);
  605.     }
  606.     /**
  607.      * {@inheritDoc}
  608.      */
  609.     protected function getFqcnFromAlias($namespaceAlias$simpleClassName)
  610.     {
  611.         /** @psalm-var class-string */
  612.         return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' $simpleClassName;
  613.     }
  614.     /**
  615.      * {@inheritDoc}
  616.      */
  617.     protected function getDriver()
  618.     {
  619.         return $this->driver;
  620.     }
  621.     /**
  622.      * {@inheritDoc}
  623.      */
  624.     protected function isEntity(ClassMetadataInterface $class)
  625.     {
  626.         return ! $class->isMappedSuperclass;
  627.     }
  628.     private function getTargetPlatform(): Platforms\AbstractPlatform
  629.     {
  630.         if (! $this->targetPlatform) {
  631.             $this->targetPlatform $this->em->getConnection()->getDatabasePlatform();
  632.         }
  633.         return $this->targetPlatform;
  634.     }
  635. }