summaryrefslogtreecommitdiff
path: root/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2024-08-13 23:45:21 +0200
committerpolo <ordipolo@gmx.fr>2024-08-13 23:45:21 +0200
commitbf6655a534a6775d30cafa67bd801276bda1d98d (patch)
treec6381e3f6c81c33eab72508f410b165ba05f7e9c /vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php
parent94d67a4b51f8e62e7d518cce26a526ae1ec48278 (diff)
downloadAppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.zip
VERSION 0.2 doctrine ORM et entités
Diffstat (limited to 'vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php')
-rw-r--r--vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php729
1 files changed, 729 insertions, 0 deletions
diff --git a/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php b/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php
new file mode 100644
index 0000000..a3a4701
--- /dev/null
+++ b/vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php
@@ -0,0 +1,729 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\ORM\Mapping;
6
7use Doctrine\Common\EventManager;
8use Doctrine\DBAL\Platforms;
9use Doctrine\DBAL\Platforms\AbstractPlatform;
10use Doctrine\Deprecations\Deprecation;
11use Doctrine\ORM\EntityManagerInterface;
12use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
13use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
14use Doctrine\ORM\Events;
15use Doctrine\ORM\Exception\ORMException;
16use Doctrine\ORM\Id\AssignedGenerator;
17use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
18use Doctrine\ORM\Id\IdentityGenerator;
19use Doctrine\ORM\Id\SequenceGenerator;
20use Doctrine\ORM\Mapping\Exception\InvalidCustomGenerator;
21use Doctrine\ORM\Mapping\Exception\UnknownGeneratorType;
22use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
23use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
24use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
25use Doctrine\Persistence\Mapping\Driver\MappingDriver;
26use Doctrine\Persistence\Mapping\ReflectionService;
27use ReflectionClass;
28use ReflectionException;
29
30use function assert;
31use function class_exists;
32use function count;
33use function end;
34use function explode;
35use function in_array;
36use function is_a;
37use function is_subclass_of;
38use function method_exists;
39use function str_contains;
40use function strlen;
41use function strtolower;
42use function substr;
43
44/**
45 * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
46 * metadata mapping information of a class which describes how a class should be mapped
47 * to a relational database.
48 *
49 * @extends AbstractClassMetadataFactory<ClassMetadata>
50 */
51class ClassMetadataFactory extends AbstractClassMetadataFactory
52{
53 private EntityManagerInterface|null $em = null;
54 private AbstractPlatform|null $targetPlatform = null;
55 private MappingDriver|null $driver = null;
56 private EventManager|null $evm = null;
57
58 /** @var mixed[] */
59 private array $embeddablesActiveNesting = [];
60
61 private const NON_IDENTITY_DEFAULT_STRATEGY = [
62 Platforms\OraclePlatform::class => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
63 ];
64
65 public function setEntityManager(EntityManagerInterface $em): void
66 {
67 parent::setProxyClassNameResolver(new DefaultProxyClassNameResolver());
68
69 $this->em = $em;
70 }
71
72 /**
73 * @param A $maybeOwningSide
74 *
75 * @return (A is ManyToManyAssociationMapping ? ManyToManyOwningSideMapping : (
76 * A is OneToOneAssociationMapping ? OneToOneOwningSideMapping : (
77 * A is OneToManyAssociationMapping ? ManyToOneAssociationMapping : (
78 * A is ManyToOneAssociationMapping ? ManyToOneAssociationMapping :
79 * ManyToManyOwningSideMapping|OneToOneOwningSideMapping|ManyToOneAssociationMapping
80 * ))))
81 *
82 * @template A of AssociationMapping
83 */
84 final public function getOwningSide(AssociationMapping $maybeOwningSide): OwningSideMapping
85 {
86 if ($maybeOwningSide instanceof OwningSideMapping) {
87 assert($maybeOwningSide instanceof ManyToManyOwningSideMapping ||
88 $maybeOwningSide instanceof OneToOneOwningSideMapping ||
89 $maybeOwningSide instanceof ManyToOneAssociationMapping);
90
91 return $maybeOwningSide;
92 }
93
94 assert($maybeOwningSide instanceof InverseSideMapping);
95
96 $owningSide = $this->getMetadataFor($maybeOwningSide->targetEntity)
97 ->associationMappings[$maybeOwningSide->mappedBy];
98
99 assert($owningSide instanceof ManyToManyOwningSideMapping ||
100 $owningSide instanceof OneToOneOwningSideMapping ||
101 $owningSide instanceof ManyToOneAssociationMapping);
102
103 return $owningSide;
104 }
105
106 protected function initialize(): void
107 {
108 $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl();
109 $this->evm = $this->em->getEventManager();
110 $this->initialized = true;
111 }
112
113 protected function onNotFoundMetadata(string $className): ClassMetadata|null
114 {
115 if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) {
116 return null;
117 }
118
119 $eventArgs = new OnClassMetadataNotFoundEventArgs($className, $this->em);
120
121 $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs);
122 $classMetadata = $eventArgs->getFoundMetadata();
123 assert($classMetadata instanceof ClassMetadata || $classMetadata === null);
124
125 return $classMetadata;
126 }
127
128 /**
129 * {@inheritDoc}
130 */
131 protected function doLoadMetadata(
132 ClassMetadataInterface $class,
133 ClassMetadataInterface|null $parent,
134 bool $rootEntityFound,
135 array $nonSuperclassParents,
136 ): void {
137 if ($parent) {
138 $class->setInheritanceType($parent->inheritanceType);
139 $class->setDiscriminatorColumn($parent->discriminatorColumn === null ? null : clone $parent->discriminatorColumn);
140 $class->setIdGeneratorType($parent->generatorType);
141 $this->addInheritedFields($class, $parent);
142 $this->addInheritedRelations($class, $parent);
143 $this->addInheritedEmbeddedClasses($class, $parent);
144 $class->setIdentifier($parent->identifier);
145 $class->setVersioned($parent->isVersioned);
146 $class->setVersionField($parent->versionField);
147 $class->setDiscriminatorMap($parent->discriminatorMap);
148 $class->addSubClasses($parent->subClasses);
149 $class->setLifecycleCallbacks($parent->lifecycleCallbacks);
150 $class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
151
152 if (! empty($parent->customGeneratorDefinition)) {
153 $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition);
154 }
155
156 if ($parent->isMappedSuperclass) {
157 $class->setCustomRepositoryClass($parent->customRepositoryClassName);
158 }
159 }
160
161 // Invoke driver
162 try {
163 $this->driver->loadMetadataForClass($class->getName(), $class);
164 } catch (ReflectionException $e) {
165 throw MappingException::reflectionFailure($class->getName(), $e);
166 }
167
168 // If this class has a parent the id generator strategy is inherited.
169 // However this is only true if the hierarchy of parents contains the root entity,
170 // if it consists of mapped superclasses these don't necessarily include the id field.
171 if ($parent && $rootEntityFound) {
172 $this->inheritIdGeneratorMapping($class, $parent);
173 } else {
174 $this->completeIdGeneratorMapping($class);
175 }
176
177 if (! $class->isMappedSuperclass) {
178 if ($rootEntityFound && $class->isInheritanceTypeNone()) {
179 throw MappingException::missingInheritanceTypeDeclaration(end($nonSuperclassParents), $class->name);
180 }
181
182 foreach ($class->embeddedClasses as $property => $embeddableClass) {
183 if (isset($embeddableClass->inherited)) {
184 continue;
185 }
186
187 if (isset($this->embeddablesActiveNesting[$embeddableClass->class])) {
188 throw MappingException::infiniteEmbeddableNesting($class->name, $property);
189 }
190
191 $this->embeddablesActiveNesting[$class->name] = true;
192
193 $embeddableMetadata = $this->getMetadataFor($embeddableClass->class);
194
195 if ($embeddableMetadata->isEmbeddedClass) {
196 $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property);
197 }
198
199 $identifier = $embeddableMetadata->getIdentifier();
200
201 if (! empty($identifier)) {
202 $this->inheritIdGeneratorMapping($class, $embeddableMetadata);
203 }
204
205 $class->inlineEmbeddable($property, $embeddableMetadata);
206
207 unset($this->embeddablesActiveNesting[$class->name]);
208 }
209 }
210
211 if ($parent) {
212 if ($parent->isInheritanceTypeSingleTable()) {
213 $class->setPrimaryTable($parent->table);
214 }
215
216 $this->addInheritedIndexes($class, $parent);
217
218 if ($parent->cache) {
219 $class->cache = $parent->cache;
220 }
221
222 if ($parent->containsForeignIdentifier) {
223 $class->containsForeignIdentifier = true;
224 }
225
226 if ($parent->containsEnumIdentifier) {
227 $class->containsEnumIdentifier = true;
228 }
229
230 if (! empty($parent->entityListeners) && empty($class->entityListeners)) {
231 $class->entityListeners = $parent->entityListeners;
232 }
233 }
234
235 $class->setParentClasses($nonSuperclassParents);
236
237 if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) {
238 $this->addDefaultDiscriminatorMap($class);
239 }
240
241 // During the following event, there may also be updates to the discriminator map as per GH-1257/GH-8402.
242 // So, we must not discover the missing subclasses before that.
243
244 if ($this->evm->hasListeners(Events::loadClassMetadata)) {
245 $eventArgs = new LoadClassMetadataEventArgs($class, $this->em);
246 $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
247 }
248
249 $this->findAbstractEntityClassesNotListedInDiscriminatorMap($class);
250
251 $this->validateRuntimeMetadata($class, $parent);
252 }
253
254 /**
255 * Validate runtime metadata is correctly defined.
256 *
257 * @throws MappingException
258 */
259 protected function validateRuntimeMetadata(ClassMetadata $class, ClassMetadataInterface|null $parent): void
260 {
261 if (! $class->reflClass) {
262 // only validate if there is a reflection class instance
263 return;
264 }
265
266 $class->validateIdentifier();
267 $class->validateAssociations();
268 $class->validateLifecycleCallbacks($this->getReflectionService());
269
270 // verify inheritance
271 if (! $class->isMappedSuperclass && ! $class->isInheritanceTypeNone()) {
272 if (! $parent) {
273 if (count($class->discriminatorMap) === 0) {
274 throw MappingException::missingDiscriminatorMap($class->name);
275 }
276
277 if (! $class->discriminatorColumn) {
278 throw MappingException::missingDiscriminatorColumn($class->name);
279 }
280
281 foreach ($class->subClasses as $subClass) {
282 if ((new ReflectionClass($subClass))->name !== $subClass) {
283 throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name);
284 }
285 }
286 } else {
287 assert($parent instanceof ClassMetadata); // https://github.com/doctrine/orm/issues/8746
288 if (
289 ! $class->reflClass->isAbstract()
290 && ! in_array($class->name, $class->discriminatorMap, true)
291 ) {
292 throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName);
293 }
294 }
295 } elseif ($class->isMappedSuperclass && $class->name === $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
296 // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
297 throw MappingException::noInheritanceOnMappedSuperClass($class->name);
298 }
299 }
300
301 protected function newClassMetadataInstance(string $className): ClassMetadata
302 {
303 return new ClassMetadata(
304 $className,
305 $this->em->getConfiguration()->getNamingStrategy(),
306 $this->em->getConfiguration()->getTypedFieldMapper(),
307 );
308 }
309
310 /**
311 * Adds a default discriminator map if no one is given
312 *
313 * If an entity is of any inheritance type and does not contain a
314 * discriminator map, then the map is generated automatically. This process
315 * is expensive computation wise.
316 *
317 * The automatically generated discriminator map contains the lowercase short name of
318 * each class as key.
319 *
320 * @throws MappingException
321 */
322 private function addDefaultDiscriminatorMap(ClassMetadata $class): void
323 {
324 $allClasses = $this->driver->getAllClassNames();
325 $fqcn = $class->getName();
326 $map = [$this->getShortName($class->name) => $fqcn];
327
328 $duplicates = [];
329 foreach ($allClasses as $subClassCandidate) {
330 if (is_subclass_of($subClassCandidate, $fqcn)) {
331 $shortName = $this->getShortName($subClassCandidate);
332
333 if (isset($map[$shortName])) {
334 $duplicates[] = $shortName;
335 }
336
337 $map[$shortName] = $subClassCandidate;
338 }
339 }
340
341 if ($duplicates) {
342 throw MappingException::duplicateDiscriminatorEntry($class->name, $duplicates, $map);
343 }
344
345 $class->setDiscriminatorMap($map);
346 }
347
348 private function findAbstractEntityClassesNotListedInDiscriminatorMap(ClassMetadata $rootEntityClass): void
349 {
350 // Only root classes in inheritance hierarchies need contain a discriminator map,
351 // so skip for other classes.
352 if (! $rootEntityClass->isRootEntity() || $rootEntityClass->isInheritanceTypeNone()) {
353 return;
354 }
355
356 $processedClasses = [$rootEntityClass->name => true];
357 foreach ($rootEntityClass->subClasses as $knownSubClass) {
358 $processedClasses[$knownSubClass] = true;
359 }
360
361 foreach ($rootEntityClass->discriminatorMap as $declaredClassName) {
362 // This fetches non-transient parent classes only
363 $parentClasses = $this->getParentClasses($declaredClassName);
364
365 foreach ($parentClasses as $parentClass) {
366 if (isset($processedClasses[$parentClass])) {
367 continue;
368 }
369
370 $processedClasses[$parentClass] = true;
371
372 // All non-abstract entity classes must be listed in the discriminator map, and
373 // this will be validated/enforced at runtime (possibly at a later time, when the
374 // subclass is loaded, but anyways). Also, subclasses is about entity classes only.
375 // That means we can ignore non-abstract classes here. The (expensive) driver
376 // check for mapped superclasses need only be run for abstract candidate classes.
377 if (! (new ReflectionClass($parentClass))->isAbstract() || $this->peekIfIsMappedSuperclass($parentClass)) {
378 continue;
379 }
380
381 // We have found a non-transient, non-mapped-superclass = an entity class (possibly abstract, but that does not matter)
382 $rootEntityClass->addSubClass($parentClass);
383 }
384 }
385 }
386
387 /** @param class-string $className */
388 private function peekIfIsMappedSuperclass(string $className): bool
389 {
390 $reflService = $this->getReflectionService();
391 $class = $this->newClassMetadataInstance($className);
392 $this->initializeReflection($class, $reflService);
393
394 $this->getDriver()->loadMetadataForClass($className, $class);
395
396 return $class->isMappedSuperclass;
397 }
398
399 /**
400 * Gets the lower-case short name of a class.
401 *
402 * @psalm-param class-string $className
403 */
404 private function getShortName(string $className): string
405 {
406 if (! str_contains($className, '\\')) {
407 return strtolower($className);
408 }
409
410 $parts = explode('\\', $className);
411
412 return strtolower(end($parts));
413 }
414
415 /**
416 * Puts the `inherited` and `declared` values into mapping information for fields, associations
417 * and embedded classes.
418 */
419 private function addMappingInheritanceInformation(
420 AssociationMapping|EmbeddedClassMapping|FieldMapping $mapping,
421 ClassMetadata $parentClass,
422 ): void {
423 if (! isset($mapping->inherited) && ! $parentClass->isMappedSuperclass) {
424 $mapping->inherited = $parentClass->name;
425 }
426
427 if (! isset($mapping->declared)) {
428 $mapping->declared = $parentClass->name;
429 }
430 }
431
432 /**
433 * Adds inherited fields to the subclass mapping.
434 */
435 private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass): void
436 {
437 foreach ($parentClass->fieldMappings as $mapping) {
438 $subClassMapping = clone $mapping;
439 $this->addMappingInheritanceInformation($subClassMapping, $parentClass);
440 $subClass->addInheritedFieldMapping($subClassMapping);
441 }
442
443 foreach ($parentClass->reflFields as $name => $field) {
444 $subClass->reflFields[$name] = $field;
445 }
446 }
447
448 /**
449 * Adds inherited association mappings to the subclass mapping.
450 *
451 * @throws MappingException
452 */
453 private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass): void
454 {
455 foreach ($parentClass->associationMappings as $field => $mapping) {
456 $subClassMapping = clone $mapping;
457 $this->addMappingInheritanceInformation($subClassMapping, $parentClass);
458 // When the class inheriting the relation ($subClass) is the first entity class since the
459 // relation has been defined in a mapped superclass (or in a chain
460 // of mapped superclasses) above, then declare this current entity class as the source of
461 // the relationship.
462 // According to the definitions given in https://github.com/doctrine/orm/pull/10396/,
463 // this is the case <=> ! isset($mapping['inherited']).
464 if (! isset($subClassMapping->inherited)) {
465 $subClassMapping->sourceEntity = $subClass->name;
466 }
467
468 $subClass->addInheritedAssociationMapping($subClassMapping);
469 }
470 }
471
472 private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass): void
473 {
474 foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
475 $subClassMapping = clone $embeddedClass;
476 $this->addMappingInheritanceInformation($subClassMapping, $parentClass);
477 $subClass->embeddedClasses[$field] = $subClassMapping;
478 }
479 }
480
481 /**
482 * Adds nested embedded classes metadata to a parent class.
483 *
484 * @param ClassMetadata $subClass Sub embedded class metadata to add nested embedded classes metadata from.
485 * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to.
486 * @param string $prefix Embedded classes' prefix to use for nested embedded classes field names.
487 */
488 private function addNestedEmbeddedClasses(
489 ClassMetadata $subClass,
490 ClassMetadata $parentClass,
491 string $prefix,
492 ): void {
493 foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
494 if (isset($embeddableClass->inherited)) {
495 continue;
496 }
497
498 $embeddableMetadata = $this->getMetadataFor($embeddableClass->class);
499
500 $parentClass->mapEmbedded(
501 [
502 'fieldName' => $prefix . '.' . $property,
503 'class' => $embeddableMetadata->name,
504 'columnPrefix' => $embeddableClass->columnPrefix,
505 'declaredField' => $embeddableClass->declaredField
506 ? $prefix . '.' . $embeddableClass->declaredField
507 : $prefix,
508 'originalField' => $embeddableClass->originalField ?: $property,
509 ],
510 );
511 }
512 }
513
514 /**
515 * Copy the table indices from the parent class superclass to the child class
516 */
517 private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass): void
518 {
519 if (! $parentClass->isMappedSuperclass) {
520 return;
521 }
522
523 foreach (['uniqueConstraints', 'indexes'] as $indexType) {
524 if (isset($parentClass->table[$indexType])) {
525 foreach ($parentClass->table[$indexType] as $indexName => $index) {
526 if (isset($subClass->table[$indexType][$indexName])) {
527 continue; // Let the inheriting table override indices
528 }
529
530 $subClass->table[$indexType][$indexName] = $index;
531 }
532 }
533 }
534 }
535
536 /**
537 * Completes the ID generator mapping. If "auto" is specified we choose the generator
538 * most appropriate for the targeted database platform.
539 *
540 * @throws ORMException
541 */
542 private function completeIdGeneratorMapping(ClassMetadata $class): void
543 {
544 $idGenType = $class->generatorType;
545 if ($idGenType === ClassMetadata::GENERATOR_TYPE_AUTO) {
546 $class->setIdGeneratorType($this->determineIdGeneratorStrategy($this->getTargetPlatform()));
547 }
548
549 // Create & assign an appropriate ID generator instance
550 switch ($class->generatorType) {
551 case ClassMetadata::GENERATOR_TYPE_IDENTITY:
552 $sequenceName = null;
553 $fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null;
554 $platform = $this->getTargetPlatform();
555
556 $generator = $fieldName && $class->fieldMappings[$fieldName]->type === 'bigint'
557 ? new BigIntegerIdentityGenerator()
558 : new IdentityGenerator();
559
560 $class->setIdGenerator($generator);
561
562 break;
563
564 case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
565 // If there is no sequence definition yet, create a default definition
566 $definition = $class->sequenceGeneratorDefinition;
567
568 if (! $definition) {
569 $fieldName = $class->getSingleIdentifierFieldName();
570 $sequenceName = $class->getSequenceName($this->getTargetPlatform());
571 $quoted = isset($class->fieldMappings[$fieldName]->quoted) || isset($class->table['quoted']);
572
573 $definition = [
574 'sequenceName' => $this->truncateSequenceName($sequenceName),
575 'allocationSize' => 1,
576 'initialValue' => 1,
577 ];
578
579 if ($quoted) {
580 $definition['quoted'] = true;
581 }
582
583 $class->setSequenceGeneratorDefinition($definition);
584 }
585
586 $sequenceGenerator = new SequenceGenerator(
587 $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->getTargetPlatform()),
588 (int) $definition['allocationSize'],
589 );
590 $class->setIdGenerator($sequenceGenerator);
591 break;
592
593 case ClassMetadata::GENERATOR_TYPE_NONE:
594 $class->setIdGenerator(new AssignedGenerator());
595 break;
596
597 case ClassMetadata::GENERATOR_TYPE_CUSTOM:
598 $definition = $class->customGeneratorDefinition;
599 if ($definition === null) {
600 throw InvalidCustomGenerator::onClassNotConfigured();
601 }
602
603 if (! class_exists($definition['class'])) {
604 throw InvalidCustomGenerator::onMissingClass($definition);
605 }
606
607 $class->setIdGenerator(new $definition['class']());
608 break;
609
610 default:
611 throw UnknownGeneratorType::create($class->generatorType);
612 }
613 }
614
615 /** @psalm-return ClassMetadata::GENERATOR_TYPE_* */
616 private function determineIdGeneratorStrategy(AbstractPlatform $platform): int
617 {
618 assert($this->em !== null);
619 foreach ($this->em->getConfiguration()->getIdentityGenerationPreferences() as $platformFamily => $strategy) {
620 if (is_a($platform, $platformFamily)) {
621 return $strategy;
622 }
623 }
624
625 $nonIdentityDefaultStrategy = self::NON_IDENTITY_DEFAULT_STRATEGY;
626
627 // DBAL 3
628 if (method_exists($platform, 'getIdentitySequenceName')) {
629 $nonIdentityDefaultStrategy[Platforms\PostgreSQLPlatform::class] = ClassMetadata::GENERATOR_TYPE_SEQUENCE;
630 }
631
632 foreach ($nonIdentityDefaultStrategy as $platformFamily => $strategy) {
633 if (is_a($platform, $platformFamily)) {
634 if ($platform instanceof Platforms\PostgreSQLPlatform) {
635 Deprecation::trigger(
636 'doctrine/orm',
637 'https://github.com/doctrine/orm/issues/8893',
638 <<<'DEPRECATION'
639 Relying on non-optimal defaults for ID generation is deprecated, and IDENTITY
640 results in SERIAL, which is not recommended.
641 Instead, configure identifier generation strategies explicitly through
642 configuration.
643 We currently recommend "SEQUENCE" for "%s", when using DBAL 3,
644 and "IDENTITY" when using DBAL 4,
645 so you should probably use the following configuration before upgrading to DBAL 4,
646 and remove it after deploying that upgrade:
647
648 $configuration->setIdentityGenerationPreferences([
649 "%s" => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
650 ]);
651
652 DEPRECATION,
653 $platformFamily,
654 $platformFamily,
655 );
656 }
657
658 return $strategy;
659 }
660 }
661
662 return ClassMetadata::GENERATOR_TYPE_IDENTITY;
663 }
664
665 private function truncateSequenceName(string $schemaElementName): string
666 {
667 $platform = $this->getTargetPlatform();
668 if (! $platform instanceof Platforms\OraclePlatform) {
669 return $schemaElementName;
670 }
671
672 $maxIdentifierLength = $platform->getMaxIdentifierLength();
673
674 if (strlen($schemaElementName) > $maxIdentifierLength) {
675 return substr($schemaElementName, 0, $maxIdentifierLength);
676 }
677
678 return $schemaElementName;
679 }
680
681 /**
682 * Inherits the ID generator mapping from a parent class.
683 */
684 private function inheritIdGeneratorMapping(ClassMetadata $class, ClassMetadata $parent): void
685 {
686 if ($parent->isIdGeneratorSequence()) {
687 $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
688 }
689
690 if ($parent->generatorType) {
691 $class->setIdGeneratorType($parent->generatorType);
692 }
693
694 if ($parent->idGenerator ?? null) {
695 $class->setIdGenerator($parent->idGenerator);
696 }
697 }
698
699 protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService): void
700 {
701 $class->wakeupReflection($reflService);
702 }
703
704 protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService): void
705 {
706 $class->initializeReflection($reflService);
707 }
708
709 protected function getDriver(): MappingDriver
710 {
711 assert($this->driver !== null);
712
713 return $this->driver;
714 }
715
716 protected function isEntity(ClassMetadataInterface $class): bool
717 {
718 return ! $class->isMappedSuperclass;
719 }
720
721 private function getTargetPlatform(): Platforms\AbstractPlatform
722 {
723 if (! $this->targetPlatform) {
724 $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform();
725 }
726
727 return $this->targetPlatform;
728 }
729}