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

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