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

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 get_class;
  33. use function in_array;
  34. use function is_subclass_of;
  35. use function str_contains;
  36. use function strlen;
  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.  * @extends AbstractClassMetadataFactory<ClassMetadata>
  45.  */
  46. class ClassMetadataFactory extends AbstractClassMetadataFactory
  47. {
  48.     /** @var EntityManagerInterface|null */
  49.     private $em;
  50.     /** @var AbstractPlatform|null */
  51.     private $targetPlatform;
  52.     /** @var MappingDriver */
  53.     private $driver;
  54.     /** @var EventManager */
  55.     private $evm;
  56.     /** @var mixed[] */
  57.     private $embeddablesActiveNesting = [];
  58.     /** @return void */
  59.     public function setEntityManager(EntityManagerInterface $em)
  60.     {
  61.         $this->em $em;
  62.     }
  63.     /**
  64.      * {@inheritDoc}
  65.      */
  66.     protected function initialize()
  67.     {
  68.         $this->driver      $this->em->getConfiguration()->getMetadataDriverImpl();
  69.         $this->evm         $this->em->getEventManager();
  70.         $this->initialized true;
  71.     }
  72.     /**
  73.      * {@inheritDoc}
  74.      */
  75.     protected function onNotFoundMetadata($className)
  76.     {
  77.         if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) {
  78.             return null;
  79.         }
  80.         $eventArgs = new OnClassMetadataNotFoundEventArgs($className$this->em);
  81.         $this->evm->dispatchEvent(Events::onClassMetadataNotFound$eventArgs);
  82.         $classMetadata $eventArgs->getFoundMetadata();
  83.         assert($classMetadata instanceof ClassMetadata || $classMetadata === null);
  84.         return $classMetadata;
  85.     }
  86.     /**
  87.      * {@inheritDoc}
  88.      */
  89.     protected function doLoadMetadata($class$parent$rootEntityFound, array $nonSuperclassParents)
  90.     {
  91.         if ($parent) {
  92.             $class->setInheritanceType($parent->inheritanceType);
  93.             $class->setDiscriminatorColumn($parent->discriminatorColumn);
  94.             $class->setIdGeneratorType($parent->generatorType);
  95.             $this->addInheritedFields($class$parent);
  96.             $this->addInheritedRelations($class$parent);
  97.             $this->addInheritedEmbeddedClasses($class$parent);
  98.             $class->setIdentifier($parent->identifier);
  99.             $class->setVersioned($parent->isVersioned);
  100.             $class->setVersionField($parent->versionField);
  101.             $class->setDiscriminatorMap($parent->discriminatorMap);
  102.             $class->addSubClasses($parent->subClasses);
  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.         // During the following event, there may also be updates to the discriminator map as per GH-1257/GH-8402.
  182.         // So, we must not discover the missing subclasses before that.
  183.         if ($this->evm->hasListeners(Events::loadClassMetadata)) {
  184.             $eventArgs = new LoadClassMetadataEventArgs($class$this->em);
  185.             $this->evm->dispatchEvent(Events::loadClassMetadata$eventArgs);
  186.         }
  187.         $this->findAbstractEntityClassesNotListedInDiscriminatorMap($class);
  188.         if ($class->changeTrackingPolicy === ClassMetadata::CHANGETRACKING_NOTIFY) {
  189.             Deprecation::trigger(
  190.                 'doctrine/orm',
  191.                 'https://github.com/doctrine/orm/issues/8383',
  192.                 'NOTIFY Change Tracking policy used in "%s" is deprecated, use deferred explicit instead.',
  193.                 $class->name
  194.             );
  195.         }
  196.         $this->validateRuntimeMetadata($class$parent);
  197.     }
  198.     /**
  199.      * Validate runtime metadata is correctly defined.
  200.      *
  201.      * @param ClassMetadata               $class
  202.      * @param ClassMetadataInterface|null $parent
  203.      *
  204.      * @return void
  205.      *
  206.      * @throws MappingException
  207.      */
  208.     protected function validateRuntimeMetadata($class$parent)
  209.     {
  210.         if (! $class->reflClass) {
  211.             // only validate if there is a reflection class instance
  212.             return;
  213.         }
  214.         $class->validateIdentifier();
  215.         $class->validateAssociations();
  216.         $class->validateLifecycleCallbacks($this->getReflectionService());
  217.         // verify inheritance
  218.         if (! $class->isMappedSuperclass && ! $class->isInheritanceTypeNone()) {
  219.             if (! $parent) {
  220.                 if (count($class->discriminatorMap) === 0) {
  221.                     throw MappingException::missingDiscriminatorMap($class->name);
  222.                 }
  223.                 if (! $class->discriminatorColumn) {
  224.                     throw MappingException::missingDiscriminatorColumn($class->name);
  225.                 }
  226.                 foreach ($class->subClasses as $subClass) {
  227.                     if ((new ReflectionClass($subClass))->name !== $subClass) {
  228.                         throw MappingException::invalidClassInDiscriminatorMap($subClass$class->name);
  229.                     }
  230.                 }
  231.             } else {
  232.                 assert($parent instanceof ClassMetadataInfo); // https://github.com/doctrine/orm/issues/8746
  233.                 if (
  234.                     ! $class->reflClass->isAbstract()
  235.                     && ! in_array($class->name$class->discriminatorMaptrue)
  236.                 ) {
  237.                     throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name$class->rootEntityName);
  238.                 }
  239.             }
  240.         } elseif ($class->isMappedSuperclass && $class->name === $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
  241.             // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
  242.             throw MappingException::noInheritanceOnMappedSuperClass($class->name);
  243.         }
  244.     }
  245.     /**
  246.      * {@inheritDoc}
  247.      */
  248.     protected function newClassMetadataInstance($className)
  249.     {
  250.         return new ClassMetadata(
  251.             $className,
  252.             $this->em->getConfiguration()->getNamingStrategy(),
  253.             $this->em->getConfiguration()->getTypedFieldMapper()
  254.         );
  255.     }
  256.     /**
  257.      * Adds a default discriminator map if no one is given
  258.      *
  259.      * If an entity is of any inheritance type and does not contain a
  260.      * discriminator map, then the map is generated automatically. This process
  261.      * is expensive computation wise.
  262.      *
  263.      * The automatically generated discriminator map contains the lowercase short name of
  264.      * each class as key.
  265.      *
  266.      * @throws MappingException
  267.      */
  268.     private function addDefaultDiscriminatorMap(ClassMetadata $class): void
  269.     {
  270.         $allClasses $this->driver->getAllClassNames();
  271.         $fqcn       $class->getName();
  272.         $map        = [$this->getShortName($class->name) => $fqcn];
  273.         $duplicates = [];
  274.         foreach ($allClasses as $subClassCandidate) {
  275.             if (is_subclass_of($subClassCandidate$fqcn)) {
  276.                 $shortName $this->getShortName($subClassCandidate);
  277.                 if (isset($map[$shortName])) {
  278.                     $duplicates[] = $shortName;
  279.                 }
  280.                 $map[$shortName] = $subClassCandidate;
  281.             }
  282.         }
  283.         if ($duplicates) {
  284.             throw MappingException::duplicateDiscriminatorEntry($class->name$duplicates$map);
  285.         }
  286.         $class->setDiscriminatorMap($map);
  287.     }
  288.     private function findAbstractEntityClassesNotListedInDiscriminatorMap(ClassMetadata $rootEntityClass): void
  289.     {
  290.         // Only root classes in inheritance hierarchies need contain a discriminator map,
  291.         // so skip for other classes.
  292.         if (! $rootEntityClass->isRootEntity() || $rootEntityClass->isInheritanceTypeNone()) {
  293.             return;
  294.         }
  295.         $processedClasses = [$rootEntityClass->name => true];
  296.         foreach ($rootEntityClass->subClasses as $knownSubClass) {
  297.             $processedClasses[$knownSubClass] = true;
  298.         }
  299.         foreach ($rootEntityClass->discriminatorMap as $declaredClassName) {
  300.             // This fetches non-transient parent classes only
  301.             $parentClasses $this->getParentClasses($declaredClassName);
  302.             foreach ($parentClasses as $parentClass) {
  303.                 if (isset($processedClasses[$parentClass])) {
  304.                     continue;
  305.                 }
  306.                 $processedClasses[$parentClass] = true;
  307.                 // All non-abstract entity classes must be listed in the discriminator map, and
  308.                 // this will be validated/enforced at runtime (possibly at a later time, when the
  309.                 // subclass is loaded, but anyways). Also, subclasses is about entity classes only.
  310.                 // That means we can ignore non-abstract classes here. The (expensive) driver
  311.                 // check for mapped superclasses need only be run for abstract candidate classes.
  312.                 if (! (new ReflectionClass($parentClass))->isAbstract() || $this->peekIfIsMappedSuperclass($parentClass)) {
  313.                     continue;
  314.                 }
  315.                 // We have found a non-transient, non-mapped-superclass = an entity class (possibly abstract, but that does not matter)
  316.                 $rootEntityClass->addSubClass($parentClass);
  317.             }
  318.         }
  319.     }
  320.     /** @param class-string $className */
  321.     private function peekIfIsMappedSuperclass(string $className): bool
  322.     {
  323.         $reflService $this->getReflectionService();
  324.         $class       $this->newClassMetadataInstance($className);
  325.         $this->initializeReflection($class$reflService);
  326.         $this->driver->loadMetadataForClass($className$class);
  327.         return $class->isMappedSuperclass;
  328.     }
  329.     /**
  330.      * Gets the lower-case short name of a class.
  331.      *
  332.      * @psalm-param class-string $className
  333.      */
  334.     private function getShortName(string $className): string
  335.     {
  336.         if (! str_contains($className'\\')) {
  337.             return strtolower($className);
  338.         }
  339.         $parts explode('\\'$className);
  340.         return strtolower(end($parts));
  341.     }
  342.     /**
  343.      * Adds inherited fields to the subclass mapping.
  344.      */
  345.     private function addInheritedFields(ClassMetadata $subClassClassMetadata $parentClass): void
  346.     {
  347.         foreach ($parentClass->fieldMappings as $mapping) {
  348.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  349.                 $mapping['inherited'] = $parentClass->name;
  350.             }
  351.             if (! isset($mapping['declared'])) {
  352.                 $mapping['declared'] = $parentClass->name;
  353.             }
  354.             $subClass->addInheritedFieldMapping($mapping);
  355.         }
  356.         foreach ($parentClass->reflFields as $name => $field) {
  357.             $subClass->reflFields[$name] = $field;
  358.         }
  359.     }
  360.     /**
  361.      * Adds inherited association mappings to the subclass mapping.
  362.      *
  363.      * @throws MappingException
  364.      */
  365.     private function addInheritedRelations(ClassMetadata $subClassClassMetadata $parentClass): void
  366.     {
  367.         foreach ($parentClass->associationMappings as $field => $mapping) {
  368.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  369.                 $mapping['inherited'] = $parentClass->name;
  370.             }
  371.             if (! isset($mapping['declared'])) {
  372.                 $mapping['declared'] = $parentClass->name;
  373.             }
  374.             // When the class inheriting the relation ($subClass) is the first entity class since the
  375.             // relation has been defined in a mapped superclass (or in a chain
  376.             // of mapped superclasses) above, then declare this current entity class as the source of
  377.             // the relationship.
  378.             // According to the definitions given in https://github.com/doctrine/orm/pull/10396/,
  379.             // this is the case <=> ! isset($mapping['inherited']).
  380.             if (! isset($mapping['inherited'])) {
  381.                 if ($mapping['type'] & ClassMetadata::TO_MANY && ! $mapping['isOwningSide']) {
  382.                     throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name$field);
  383.                 }
  384.                 $mapping['sourceEntity'] = $subClass->name;
  385.             }
  386.             $subClass->addInheritedAssociationMapping($mapping);
  387.         }
  388.     }
  389.     private function addInheritedEmbeddedClasses(ClassMetadata $subClassClassMetadata $parentClass): void
  390.     {
  391.         foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
  392.             if (! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) {
  393.                 $embeddedClass['inherited'] = $parentClass->name;
  394.             }
  395.             if (! isset($embeddedClass['declared'])) {
  396.                 $embeddedClass['declared'] = $parentClass->name;
  397.             }
  398.             $subClass->embeddedClasses[$field] = $embeddedClass;
  399.         }
  400.     }
  401.     /**
  402.      * Adds nested embedded classes metadata to a parent class.
  403.      *
  404.      * @param ClassMetadata $subClass    Sub embedded class metadata to add nested embedded classes metadata from.
  405.      * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to.
  406.      * @param string        $prefix      Embedded classes' prefix to use for nested embedded classes field names.
  407.      */
  408.     private function addNestedEmbeddedClasses(
  409.         ClassMetadata $subClass,
  410.         ClassMetadata $parentClass,
  411.         string $prefix
  412.     ): void {
  413.         foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
  414.             if (isset($embeddableClass['inherited'])) {
  415.                 continue;
  416.             }
  417.             $embeddableMetadata $this->getMetadataFor($embeddableClass['class']);
  418.             $parentClass->mapEmbedded(
  419.                 [
  420.                     'fieldName' => $prefix '.' $property,
  421.                     'class' => $embeddableMetadata->name,
  422.                     'columnPrefix' => $embeddableClass['columnPrefix'],
  423.                     'declaredField' => $embeddableClass['declaredField']
  424.                             ? $prefix '.' $embeddableClass['declaredField']
  425.                             : $prefix,
  426.                     'originalField' => $embeddableClass['originalField'] ?: $property,
  427.                 ]
  428.             );
  429.         }
  430.     }
  431.     /**
  432.      * Copy the table indices from the parent class superclass to the child class
  433.      */
  434.     private function addInheritedIndexes(ClassMetadata $subClassClassMetadata $parentClass): void
  435.     {
  436.         if (! $parentClass->isMappedSuperclass) {
  437.             return;
  438.         }
  439.         foreach (['uniqueConstraints''indexes'] as $indexType) {
  440.             if (isset($parentClass->table[$indexType])) {
  441.                 foreach ($parentClass->table[$indexType] as $indexName => $index) {
  442.                     if (isset($subClass->table[$indexType][$indexName])) {
  443.                         continue; // Let the inheriting table override indices
  444.                     }
  445.                     $subClass->table[$indexType][$indexName] = $index;
  446.                 }
  447.             }
  448.         }
  449.     }
  450.     /**
  451.      * Adds inherited named queries to the subclass mapping.
  452.      */
  453.     private function addInheritedNamedQueries(ClassMetadata $subClassClassMetadata $parentClass): void
  454.     {
  455.         foreach ($parentClass->namedQueries as $name => $query) {
  456.             if (! isset($subClass->namedQueries[$name])) {
  457.                 $subClass->addNamedQuery(
  458.                     [
  459.                         'name'  => $query['name'],
  460.                         'query' => $query['query'],
  461.                     ]
  462.                 );
  463.             }
  464.         }
  465.     }
  466.     /**
  467.      * Adds inherited named native queries to the subclass mapping.
  468.      */
  469.     private function addInheritedNamedNativeQueries(ClassMetadata $subClassClassMetadata $parentClass): void
  470.     {
  471.         foreach ($parentClass->namedNativeQueries as $name => $query) {
  472.             if (! isset($subClass->namedNativeQueries[$name])) {
  473.                 $subClass->addNamedNativeQuery(
  474.                     [
  475.                         'name'              => $query['name'],
  476.                         'query'             => $query['query'],
  477.                         'isSelfClass'       => $query['isSelfClass'],
  478.                         'resultSetMapping'  => $query['resultSetMapping'],
  479.                         'resultClass'       => $query['isSelfClass'] ? $subClass->name $query['resultClass'],
  480.                     ]
  481.                 );
  482.             }
  483.         }
  484.     }
  485.     /**
  486.      * Adds inherited sql result set mappings to the subclass mapping.
  487.      */
  488.     private function addInheritedSqlResultSetMappings(ClassMetadata $subClassClassMetadata $parentClass): void
  489.     {
  490.         foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
  491.             if (! isset($subClass->sqlResultSetMappings[$name])) {
  492.                 $entities = [];
  493.                 foreach ($mapping['entities'] as $entity) {
  494.                     $entities[] = [
  495.                         'fields'                => $entity['fields'],
  496.                         'isSelfClass'           => $entity['isSelfClass'],
  497.                         'discriminatorColumn'   => $entity['discriminatorColumn'],
  498.                         'entityClass'           => $entity['isSelfClass'] ? $subClass->name $entity['entityClass'],
  499.                     ];
  500.                 }
  501.                 $subClass->addSqlResultSetMapping(
  502.                     [
  503.                         'name'          => $mapping['name'],
  504.                         'columns'       => $mapping['columns'],
  505.                         'entities'      => $entities,
  506.                     ]
  507.                 );
  508.             }
  509.         }
  510.     }
  511.     /**
  512.      * Completes the ID generator mapping. If "auto" is specified we choose the generator
  513.      * most appropriate for the targeted database platform.
  514.      *
  515.      * @throws ORMException
  516.      */
  517.     private function completeIdGeneratorMapping(ClassMetadataInfo $class): void
  518.     {
  519.         $idGenType $class->generatorType;
  520.         if ($idGenType === ClassMetadata::GENERATOR_TYPE_AUTO) {
  521.             $class->setIdGeneratorType($this->determineIdGeneratorStrategy($this->getTargetPlatform()));
  522.         }
  523.         // Create & assign an appropriate ID generator instance
  524.         switch ($class->generatorType) {
  525.             case ClassMetadata::GENERATOR_TYPE_IDENTITY:
  526.                 $sequenceName null;
  527.                 $fieldName    $class->identifier $class->getSingleIdentifierFieldName() : null;
  528.                 // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
  529.                 if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
  530.                     Deprecation::trigger(
  531.                         'doctrine/orm',
  532.                         'https://github.com/doctrine/orm/issues/8850',
  533.                         <<<'DEPRECATION'
  534. Context: Loading metadata for class %s
  535. Problem: Using the IDENTITY generator strategy with platform "%s" is deprecated and will not be possible in Doctrine ORM 3.0.
  536. Solution: Use the SEQUENCE generator strategy instead.
  537. DEPRECATION
  538.                             ,
  539.                         $class->name,
  540.                         get_class($this->getTargetPlatform())
  541.                     );
  542.                     $columnName     $class->getSingleIdentifierColumnName();
  543.                     $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
  544.                     $sequencePrefix $class->getSequencePrefix($this->getTargetPlatform());
  545.                     $sequenceName   $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix$columnName);
  546.                     $definition     = [
  547.                         'sequenceName' => $this->truncateSequenceName($sequenceName),
  548.                     ];
  549.                     if ($quoted) {
  550.                         $definition['quoted'] = true;
  551.                     }
  552.                     $sequenceName $this
  553.                         ->em
  554.                         ->getConfiguration()
  555.                         ->getQuoteStrategy()
  556.                         ->getSequenceName($definition$class$this->getTargetPlatform());
  557.                 }
  558.                 $generator $fieldName && $class->fieldMappings[$fieldName]['type'] === 'bigint'
  559.                     ? new BigIntegerIdentityGenerator($sequenceName)
  560.                     : new IdentityGenerator($sequenceName);
  561.                 $class->setIdGenerator($generator);
  562.                 break;
  563.             case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
  564.                 // If there is no sequence definition yet, create a default definition
  565.                 $definition $class->sequenceGeneratorDefinition;
  566.                 if (! $definition) {
  567.                     $fieldName    $class->getSingleIdentifierFieldName();
  568.                     $sequenceName $class->getSequenceName($this->getTargetPlatform());
  569.                     $quoted       = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
  570.                     $definition = [
  571.                         'sequenceName'      => $this->truncateSequenceName($sequenceName),
  572.                         'allocationSize'    => 1,
  573.                         'initialValue'      => 1,
  574.                     ];
  575.                     if ($quoted) {
  576.                         $definition['quoted'] = true;
  577.                     }
  578.                     $class->setSequenceGeneratorDefinition($definition);
  579.                 }
  580.                 $sequenceGenerator = new SequenceGenerator(
  581.                     $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition$class$this->getTargetPlatform()),
  582.                     (int) $definition['allocationSize']
  583.                 );
  584.                 $class->setIdGenerator($sequenceGenerator);
  585.                 break;
  586.             case ClassMetadata::GENERATOR_TYPE_NONE:
  587.                 $class->setIdGenerator(new AssignedGenerator());
  588.                 break;
  589.             case ClassMetadata::GENERATOR_TYPE_UUID:
  590.                 Deprecation::trigger(
  591.                     'doctrine/orm',
  592.                     'https://github.com/doctrine/orm/issues/7312',
  593.                     'Mapping for %s: the "UUID" id generator strategy is deprecated with no replacement',
  594.                     $class->name
  595.                 );
  596.                 $class->setIdGenerator(new UuidGenerator());
  597.                 break;
  598.             case ClassMetadata::GENERATOR_TYPE_CUSTOM:
  599.                 $definition $class->customGeneratorDefinition;
  600.                 if ($definition === null) {
  601.                     throw InvalidCustomGenerator::onClassNotConfigured();
  602.                 }
  603.                 if (! class_exists($definition['class'])) {
  604.                     throw InvalidCustomGenerator::onMissingClass($definition);
  605.                 }
  606.                 $class->setIdGenerator(new $definition['class']());
  607.                 break;
  608.             default:
  609.                 throw UnknownGeneratorType::create($class->generatorType);
  610.         }
  611.     }
  612.     /** @psalm-return ClassMetadata::GENERATOR_TYPE_SEQUENCE|ClassMetadata::GENERATOR_TYPE_IDENTITY */
  613.     private function determineIdGeneratorStrategy(AbstractPlatform $platform): int
  614.     {
  615.         if (
  616.             $platform instanceof Platforms\OraclePlatform
  617.             || $platform instanceof Platforms\PostgreSQLPlatform
  618.         ) {
  619.             return ClassMetadata::GENERATOR_TYPE_SEQUENCE;
  620.         }
  621.         if ($platform->supportsIdentityColumns()) {
  622.             return ClassMetadata::GENERATOR_TYPE_IDENTITY;
  623.         }
  624.         if ($platform->supportsSequences()) {
  625.             return ClassMetadata::GENERATOR_TYPE_SEQUENCE;
  626.         }
  627.         throw CannotGenerateIds::withPlatform($platform);
  628.     }
  629.     private function truncateSequenceName(string $schemaElementName): string
  630.     {
  631.         $platform $this->getTargetPlatform();
  632.         if (! $platform instanceof Platforms\OraclePlatform && ! $platform instanceof Platforms\SQLAnywherePlatform) {
  633.             return $schemaElementName;
  634.         }
  635.         $maxIdentifierLength $platform->getMaxIdentifierLength();
  636.         if (strlen($schemaElementName) > $maxIdentifierLength) {
  637.             return substr($schemaElementName0$maxIdentifierLength);
  638.         }
  639.         return $schemaElementName;
  640.     }
  641.     /**
  642.      * Inherits the ID generator mapping from a parent class.
  643.      */
  644.     private function inheritIdGeneratorMapping(ClassMetadataInfo $classClassMetadataInfo $parent): void
  645.     {
  646.         if ($parent->isIdGeneratorSequence()) {
  647.             $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
  648.         }
  649.         if ($parent->generatorType) {
  650.             $class->setIdGeneratorType($parent->generatorType);
  651.         }
  652.         if ($parent->idGenerator) {
  653.             $class->setIdGenerator($parent->idGenerator);
  654.         }
  655.     }
  656.     /**
  657.      * {@inheritDoc}
  658.      */
  659.     protected function wakeupReflection(ClassMetadataInterface $classReflectionService $reflService)
  660.     {
  661.         assert($class instanceof ClassMetadata);
  662.         $class->wakeupReflection($reflService);
  663.     }
  664.     /**
  665.      * {@inheritDoc}
  666.      */
  667.     protected function initializeReflection(ClassMetadataInterface $classReflectionService $reflService)
  668.     {
  669.         assert($class instanceof ClassMetadata);
  670.         $class->initializeReflection($reflService);
  671.     }
  672.     /**
  673.      * @deprecated This method will be removed in ORM 3.0.
  674.      *
  675.      * @return class-string
  676.      */
  677.     protected function getFqcnFromAlias($namespaceAlias$simpleClassName)
  678.     {
  679.         /** @psalm-var class-string */
  680.         return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' $simpleClassName;
  681.     }
  682.     /**
  683.      * {@inheritDoc}
  684.      */
  685.     protected function getDriver()
  686.     {
  687.         return $this->driver;
  688.     }
  689.     /**
  690.      * {@inheritDoc}
  691.      */
  692.     protected function isEntity(ClassMetadataInterface $class)
  693.     {
  694.         return ! $class->isMappedSuperclass;
  695.     }
  696.     private function getTargetPlatform(): Platforms\AbstractPlatform
  697.     {
  698.         if (! $this->targetPlatform) {
  699.             $this->targetPlatform $this->em->getConnection()->getDatabasePlatform();
  700.         }
  701.         return $this->targetPlatform;
  702.     }
  703. }