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

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 str_contains;
  35. use function strlen;
  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 ($parent->containsEnumIdentifier) {
  162.                 $class->containsEnumIdentifier true;
  163.             }
  164.             if (! empty($parent->namedQueries)) {
  165.                 $this->addInheritedNamedQueries($class$parent);
  166.             }
  167.             if (! empty($parent->namedNativeQueries)) {
  168.                 $this->addInheritedNamedNativeQueries($class$parent);
  169.             }
  170.             if (! empty($parent->sqlResultSetMappings)) {
  171.                 $this->addInheritedSqlResultSetMappings($class$parent);
  172.             }
  173.             if (! empty($parent->entityListeners) && empty($class->entityListeners)) {
  174.                 $class->entityListeners $parent->entityListeners;
  175.             }
  176.         }
  177.         $class->setParentClasses($nonSuperclassParents);
  178.         if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) {
  179.             $this->addDefaultDiscriminatorMap($class);
  180.         }
  181.         if ($this->evm->hasListeners(Events::loadClassMetadata)) {
  182.             $eventArgs = new LoadClassMetadataEventArgs($class$this->em);
  183.             $this->evm->dispatchEvent(Events::loadClassMetadata$eventArgs);
  184.         }
  185.         if ($class->changeTrackingPolicy === ClassMetadataInfo::CHANGETRACKING_NOTIFY) {
  186.             Deprecation::trigger(
  187.                 'doctrine/orm',
  188.                 'https://github.com/doctrine/orm/issues/8383',
  189.                 'NOTIFY Change Tracking policy used in "%s" is deprecated, use deferred explicit instead.',
  190.                 $class->name
  191.             );
  192.         }
  193.         $this->validateRuntimeMetadata($class$parent);
  194.     }
  195.     /**
  196.      * Validate runtime metadata is correctly defined.
  197.      *
  198.      * @param ClassMetadata               $class
  199.      * @param ClassMetadataInterface|null $parent
  200.      *
  201.      * @return void
  202.      *
  203.      * @throws MappingException
  204.      */
  205.     protected function validateRuntimeMetadata($class$parent)
  206.     {
  207.         if (! $class->reflClass) {
  208.             // only validate if there is a reflection class instance
  209.             return;
  210.         }
  211.         $class->validateIdentifier();
  212.         $class->validateAssociations();
  213.         $class->validateLifecycleCallbacks($this->getReflectionService());
  214.         // verify inheritance
  215.         if (! $class->isMappedSuperclass && ! $class->isInheritanceTypeNone()) {
  216.             if (! $parent) {
  217.                 if (count($class->discriminatorMap) === 0) {
  218.                     throw MappingException::missingDiscriminatorMap($class->name);
  219.                 }
  220.                 if (! $class->discriminatorColumn) {
  221.                     throw MappingException::missingDiscriminatorColumn($class->name);
  222.                 }
  223.                 foreach ($class->subClasses as $subClass) {
  224.                     if ((new ReflectionClass($subClass))->name !== $subClass) {
  225.                         throw MappingException::invalidClassInDiscriminatorMap($subClass$class->name);
  226.                     }
  227.                 }
  228.             } else {
  229.                 assert($parent instanceof ClassMetadataInfo); // https://github.com/doctrine/orm/issues/8746
  230.                 if (
  231.                     ! $class->reflClass->isAbstract()
  232.                     && ! in_array($class->name$class->discriminatorMaptrue)
  233.                 ) {
  234.                     throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name$class->rootEntityName);
  235.                 }
  236.             }
  237.         } elseif ($class->isMappedSuperclass && $class->name === $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
  238.             // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
  239.             throw MappingException::noInheritanceOnMappedSuperClass($class->name);
  240.         }
  241.     }
  242.     /**
  243.      * {@inheritDoc}
  244.      */
  245.     protected function newClassMetadataInstance($className)
  246.     {
  247.         return new ClassMetadata($className$this->em->getConfiguration()->getNamingStrategy());
  248.     }
  249.     /**
  250.      * Adds a default discriminator map if no one is given
  251.      *
  252.      * If an entity is of any inheritance type and does not contain a
  253.      * discriminator map, then the map is generated automatically. This process
  254.      * is expensive computation wise.
  255.      *
  256.      * The automatically generated discriminator map contains the lowercase short name of
  257.      * each class as key.
  258.      *
  259.      * @throws MappingException
  260.      */
  261.     private function addDefaultDiscriminatorMap(ClassMetadata $class): void
  262.     {
  263.         $allClasses $this->driver->getAllClassNames();
  264.         $fqcn       $class->getName();
  265.         $map        = [$this->getShortName($class->name) => $fqcn];
  266.         $duplicates = [];
  267.         foreach ($allClasses as $subClassCandidate) {
  268.             if (is_subclass_of($subClassCandidate$fqcn)) {
  269.                 $shortName $this->getShortName($subClassCandidate);
  270.                 if (isset($map[$shortName])) {
  271.                     $duplicates[] = $shortName;
  272.                 }
  273.                 $map[$shortName] = $subClassCandidate;
  274.             }
  275.         }
  276.         if ($duplicates) {
  277.             throw MappingException::duplicateDiscriminatorEntry($class->name$duplicates$map);
  278.         }
  279.         $class->setDiscriminatorMap($map);
  280.     }
  281.     /**
  282.      * Gets the lower-case short name of a class.
  283.      *
  284.      * @psalm-param class-string $className
  285.      */
  286.     private function getShortName(string $className): string
  287.     {
  288.         if (! str_contains($className'\\')) {
  289.             return strtolower($className);
  290.         }
  291.         $parts explode('\\'$className);
  292.         return strtolower(end($parts));
  293.     }
  294.     /**
  295.      * Adds inherited fields to the subclass mapping.
  296.      */
  297.     private function addInheritedFields(ClassMetadata $subClassClassMetadata $parentClass): void
  298.     {
  299.         foreach ($parentClass->fieldMappings as $mapping) {
  300.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  301.                 $mapping['inherited'] = $parentClass->name;
  302.             }
  303.             if (! isset($mapping['declared'])) {
  304.                 $mapping['declared'] = $parentClass->name;
  305.             }
  306.             $subClass->addInheritedFieldMapping($mapping);
  307.         }
  308.         foreach ($parentClass->reflFields as $name => $field) {
  309.             $subClass->reflFields[$name] = $field;
  310.         }
  311.     }
  312.     /**
  313.      * Adds inherited association mappings to the subclass mapping.
  314.      *
  315.      * @throws MappingException
  316.      */
  317.     private function addInheritedRelations(ClassMetadata $subClassClassMetadata $parentClass): void
  318.     {
  319.         foreach ($parentClass->associationMappings as $field => $mapping) {
  320.             if ($parentClass->isMappedSuperclass) {
  321.                 if ($mapping['type'] & ClassMetadata::TO_MANY && ! $mapping['isOwningSide']) {
  322.                     throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name$field);
  323.                 }
  324.                 $mapping['sourceEntity'] = $subClass->name;
  325.             }
  326.             //$subclassMapping = $mapping;
  327.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  328.                 $mapping['inherited'] = $parentClass->name;
  329.             }
  330.             if (! isset($mapping['declared'])) {
  331.                 $mapping['declared'] = $parentClass->name;
  332.             }
  333.             $subClass->addInheritedAssociationMapping($mapping);
  334.         }
  335.     }
  336.     private function addInheritedEmbeddedClasses(ClassMetadata $subClassClassMetadata $parentClass): void
  337.     {
  338.         foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
  339.             if (! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) {
  340.                 $embeddedClass['inherited'] = $parentClass->name;
  341.             }
  342.             if (! isset($embeddedClass['declared'])) {
  343.                 $embeddedClass['declared'] = $parentClass->name;
  344.             }
  345.             $subClass->embeddedClasses[$field] = $embeddedClass;
  346.         }
  347.     }
  348.     /**
  349.      * Adds nested embedded classes metadata to a parent class.
  350.      *
  351.      * @param ClassMetadata $subClass    Sub embedded class metadata to add nested embedded classes metadata from.
  352.      * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to.
  353.      * @param string        $prefix      Embedded classes' prefix to use for nested embedded classes field names.
  354.      */
  355.     private function addNestedEmbeddedClasses(
  356.         ClassMetadata $subClass,
  357.         ClassMetadata $parentClass,
  358.         string $prefix
  359.     ): void {
  360.         foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
  361.             if (isset($embeddableClass['inherited'])) {
  362.                 continue;
  363.             }
  364.             $embeddableMetadata $this->getMetadataFor($embeddableClass['class']);
  365.             $parentClass->mapEmbedded(
  366.                 [
  367.                     'fieldName' => $prefix '.' $property,
  368.                     'class' => $embeddableMetadata->name,
  369.                     'columnPrefix' => $embeddableClass['columnPrefix'],
  370.                     'declaredField' => $embeddableClass['declaredField']
  371.                             ? $prefix '.' $embeddableClass['declaredField']
  372.                             : $prefix,
  373.                     'originalField' => $embeddableClass['originalField'] ?: $property,
  374.                 ]
  375.             );
  376.         }
  377.     }
  378.     /**
  379.      * Copy the table indices from the parent class superclass to the child class
  380.      */
  381.     private function addInheritedIndexes(ClassMetadata $subClassClassMetadata $parentClass): void
  382.     {
  383.         if (! $parentClass->isMappedSuperclass) {
  384.             return;
  385.         }
  386.         foreach (['uniqueConstraints''indexes'] as $indexType) {
  387.             if (isset($parentClass->table[$indexType])) {
  388.                 foreach ($parentClass->table[$indexType] as $indexName => $index) {
  389.                     if (isset($subClass->table[$indexType][$indexName])) {
  390.                         continue; // Let the inheriting table override indices
  391.                     }
  392.                     $subClass->table[$indexType][$indexName] = $index;
  393.                 }
  394.             }
  395.         }
  396.     }
  397.     /**
  398.      * Adds inherited named queries to the subclass mapping.
  399.      */
  400.     private function addInheritedNamedQueries(ClassMetadata $subClassClassMetadata $parentClass): void
  401.     {
  402.         foreach ($parentClass->namedQueries as $name => $query) {
  403.             if (! isset($subClass->namedQueries[$name])) {
  404.                 $subClass->addNamedQuery(
  405.                     [
  406.                         'name'  => $query['name'],
  407.                         'query' => $query['query'],
  408.                     ]
  409.                 );
  410.             }
  411.         }
  412.     }
  413.     /**
  414.      * Adds inherited named native queries to the subclass mapping.
  415.      */
  416.     private function addInheritedNamedNativeQueries(ClassMetadata $subClassClassMetadata $parentClass): void
  417.     {
  418.         foreach ($parentClass->namedNativeQueries as $name => $query) {
  419.             if (! isset($subClass->namedNativeQueries[$name])) {
  420.                 $subClass->addNamedNativeQuery(
  421.                     [
  422.                         'name'              => $query['name'],
  423.                         'query'             => $query['query'],
  424.                         'isSelfClass'       => $query['isSelfClass'],
  425.                         'resultSetMapping'  => $query['resultSetMapping'],
  426.                         'resultClass'       => $query['isSelfClass'] ? $subClass->name $query['resultClass'],
  427.                     ]
  428.                 );
  429.             }
  430.         }
  431.     }
  432.     /**
  433.      * Adds inherited sql result set mappings to the subclass mapping.
  434.      */
  435.     private function addInheritedSqlResultSetMappings(ClassMetadata $subClassClassMetadata $parentClass): void
  436.     {
  437.         foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
  438.             if (! isset($subClass->sqlResultSetMappings[$name])) {
  439.                 $entities = [];
  440.                 foreach ($mapping['entities'] as $entity) {
  441.                     $entities[] = [
  442.                         'fields'                => $entity['fields'],
  443.                         'isSelfClass'           => $entity['isSelfClass'],
  444.                         'discriminatorColumn'   => $entity['discriminatorColumn'],
  445.                         'entityClass'           => $entity['isSelfClass'] ? $subClass->name $entity['entityClass'],
  446.                     ];
  447.                 }
  448.                 $subClass->addSqlResultSetMapping(
  449.                     [
  450.                         'name'          => $mapping['name'],
  451.                         'columns'       => $mapping['columns'],
  452.                         'entities'      => $entities,
  453.                     ]
  454.                 );
  455.             }
  456.         }
  457.     }
  458.     /**
  459.      * Completes the ID generator mapping. If "auto" is specified we choose the generator
  460.      * most appropriate for the targeted database platform.
  461.      *
  462.      * @throws ORMException
  463.      */
  464.     private function completeIdGeneratorMapping(ClassMetadataInfo $class): void
  465.     {
  466.         $idGenType $class->generatorType;
  467.         if ($idGenType === ClassMetadata::GENERATOR_TYPE_AUTO) {
  468.             $class->setIdGeneratorType($this->determineIdGeneratorStrategy($this->getTargetPlatform()));
  469.         }
  470.         // Create & assign an appropriate ID generator instance
  471.         switch ($class->generatorType) {
  472.             case ClassMetadata::GENERATOR_TYPE_IDENTITY:
  473.                 $sequenceName null;
  474.                 $fieldName    $class->identifier $class->getSingleIdentifierFieldName() : null;
  475.                 // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
  476.                 if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
  477.                     $columnName     $class->getSingleIdentifierColumnName();
  478.                     $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
  479.                     $sequencePrefix $class->getSequencePrefix($this->getTargetPlatform());
  480.                     $sequenceName   $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix$columnName);
  481.                     $definition     = [
  482.                         'sequenceName' => $this->truncateSequenceName($sequenceName),
  483.                     ];
  484.                     if ($quoted) {
  485.                         $definition['quoted'] = true;
  486.                     }
  487.                     $sequenceName $this
  488.                         ->em
  489.                         ->getConfiguration()
  490.                         ->getQuoteStrategy()
  491.                         ->getSequenceName($definition$class$this->getTargetPlatform());
  492.                 }
  493.                 $generator $fieldName && $class->fieldMappings[$fieldName]['type'] === 'bigint'
  494.                     ? new BigIntegerIdentityGenerator($sequenceName)
  495.                     : new IdentityGenerator($sequenceName);
  496.                 $class->setIdGenerator($generator);
  497.                 break;
  498.             case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
  499.                 // If there is no sequence definition yet, create a default definition
  500.                 $definition $class->sequenceGeneratorDefinition;
  501.                 if (! $definition) {
  502.                     $fieldName    $class->getSingleIdentifierFieldName();
  503.                     $sequenceName $class->getSequenceName($this->getTargetPlatform());
  504.                     $quoted       = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
  505.                     $definition = [
  506.                         'sequenceName'      => $this->truncateSequenceName($sequenceName),
  507.                         'allocationSize'    => 1,
  508.                         'initialValue'      => 1,
  509.                     ];
  510.                     if ($quoted) {
  511.                         $definition['quoted'] = true;
  512.                     }
  513.                     $class->setSequenceGeneratorDefinition($definition);
  514.                 }
  515.                 $sequenceGenerator = new SequenceGenerator(
  516.                     $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition$class$this->getTargetPlatform()),
  517.                     (int) $definition['allocationSize']
  518.                 );
  519.                 $class->setIdGenerator($sequenceGenerator);
  520.                 break;
  521.             case ClassMetadata::GENERATOR_TYPE_NONE:
  522.                 $class->setIdGenerator(new AssignedGenerator());
  523.                 break;
  524.             case ClassMetadata::GENERATOR_TYPE_UUID:
  525.                 Deprecation::trigger(
  526.                     'doctrine/orm',
  527.                     'https://github.com/doctrine/orm/issues/7312',
  528.                     'Mapping for %s: the "UUID" id generator strategy is deprecated with no replacement',
  529.                     $class->name
  530.                 );
  531.                 $class->setIdGenerator(new UuidGenerator());
  532.                 break;
  533.             case ClassMetadata::GENERATOR_TYPE_CUSTOM:
  534.                 $definition $class->customGeneratorDefinition;
  535.                 if ($definition === null) {
  536.                     throw InvalidCustomGenerator::onClassNotConfigured();
  537.                 }
  538.                 if (! class_exists($definition['class'])) {
  539.                     throw InvalidCustomGenerator::onMissingClass($definition);
  540.                 }
  541.                 $class->setIdGenerator(new $definition['class']());
  542.                 break;
  543.             default:
  544.                 throw UnknownGeneratorType::create($class->generatorType);
  545.         }
  546.     }
  547.     /**
  548.      * @psalm-return ClassMetadata::GENERATOR_TYPE_SEQUENCE|ClassMetadata::GENERATOR_TYPE_IDENTITY
  549.      */
  550.     private function determineIdGeneratorStrategy(AbstractPlatform $platform): int
  551.     {
  552.         if (
  553.             $platform instanceof Platforms\OraclePlatform
  554.             || $platform instanceof Platforms\PostgreSQLPlatform
  555.         ) {
  556.             return ClassMetadata::GENERATOR_TYPE_SEQUENCE;
  557.         }
  558.         if ($platform->supportsIdentityColumns()) {
  559.             return ClassMetadata::GENERATOR_TYPE_IDENTITY;
  560.         }
  561.         if ($platform->supportsSequences()) {
  562.             return ClassMetadata::GENERATOR_TYPE_SEQUENCE;
  563.         }
  564.         throw CannotGenerateIds::withPlatform($platform);
  565.     }
  566.     private function truncateSequenceName(string $schemaElementName): string
  567.     {
  568.         $platform $this->getTargetPlatform();
  569.         if (! $platform instanceof Platforms\OraclePlatform && ! $platform instanceof Platforms\SQLAnywherePlatform) {
  570.             return $schemaElementName;
  571.         }
  572.         $maxIdentifierLength $platform->getMaxIdentifierLength();
  573.         if (strlen($schemaElementName) > $maxIdentifierLength) {
  574.             return substr($schemaElementName0$maxIdentifierLength);
  575.         }
  576.         return $schemaElementName;
  577.     }
  578.     /**
  579.      * Inherits the ID generator mapping from a parent class.
  580.      */
  581.     private function inheritIdGeneratorMapping(ClassMetadataInfo $classClassMetadataInfo $parent): void
  582.     {
  583.         if ($parent->isIdGeneratorSequence()) {
  584.             $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
  585.         }
  586.         if ($parent->generatorType) {
  587.             $class->setIdGeneratorType($parent->generatorType);
  588.         }
  589.         if ($parent->idGenerator) {
  590.             $class->setIdGenerator($parent->idGenerator);
  591.         }
  592.     }
  593.     /**
  594.      * {@inheritDoc}
  595.      */
  596.     protected function wakeupReflection(ClassMetadataInterface $classReflectionService $reflService)
  597.     {
  598.         assert($class instanceof ClassMetadata);
  599.         $class->wakeupReflection($reflService);
  600.     }
  601.     /**
  602.      * {@inheritDoc}
  603.      */
  604.     protected function initializeReflection(ClassMetadataInterface $classReflectionService $reflService)
  605.     {
  606.         assert($class instanceof ClassMetadata);
  607.         $class->initializeReflection($reflService);
  608.     }
  609.     /**
  610.      * @deprecated This method will be removed in ORM 3.0.
  611.      *
  612.      * @return class-string
  613.      */
  614.     protected function getFqcnFromAlias($namespaceAlias$simpleClassName)
  615.     {
  616.         /** @psalm-var class-string */
  617.         return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' $simpleClassName;
  618.     }
  619.     /**
  620.      * {@inheritDoc}
  621.      */
  622.     protected function getDriver()
  623.     {
  624.         return $this->driver;
  625.     }
  626.     /**
  627.      * {@inheritDoc}
  628.      */
  629.     protected function isEntity(ClassMetadataInterface $class)
  630.     {
  631.         return ! $class->isMappedSuperclass;
  632.     }
  633.     private function getTargetPlatform(): Platforms\AbstractPlatform
  634.     {
  635.         if (! $this->targetPlatform) {
  636.             $this->targetPlatform $this->em->getConnection()->getDatabasePlatform();
  637.         }
  638.         return $this->targetPlatform;
  639.     }
  640. }