diff --git a/UPGRADE.md b/UPGRADE.md index 24d699e1371..bfc6101e783 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -9,12 +9,12 @@ Make sure to use the former when writing a type declaration or an `instanceof` c To keep PHP mapping attributes consistent, order of arguments passed to above attributes has been changed so `$targetEntity` is a first argument now. This change affects only non-named arguments usage. -## BC BREAK: AUTO keyword for identity generation defaults to IDENTITY for PostgreSQL now +## BC BREAK: AUTO keyword for identity generation defaults to IDENTITY for PostgreSQL when using `doctrine/dbal` 4 -When using the AUTO strategy to let Doctrine determine the identity generation mecehanism for -an entity, PostgreSQL now uses IDENTITY instead of SEQUENCE. When upgrading from ORM 2.x -and preference is on keeping the SEQUENCE based identity generation, then configure the ORM -this way: +When using the `AUTO` strategy to let Doctrine determine the identity generation mechanism for +an entity, and when using `doctrine/dbal` 4, PostgreSQL now uses `IDENTITY` +instead of `SEQUENCE`. When upgrading from ORM 2.x and preference is on keeping +the `SEQUENCE` based identity generation, then configure the ORM this way: ```php use Doctrine\DBAL\Platforms\PostgreSQLPlatform; diff --git a/docs/en/reference/basic-mapping.rst b/docs/en/reference/basic-mapping.rst index 818647786e7..8c31983f721 100644 --- a/docs/en/reference/basic-mapping.rst +++ b/docs/en/reference/basic-mapping.rst @@ -329,9 +329,9 @@ defaults to the identifier generation mechanism your current database vendor preferred at the time that strategy was introduced: ``AUTO_INCREMENT`` with MySQL, sequences with PostgreSQL and Oracle and so on. -We now recommend using ``IDENTITY`` for PostgreSQL, and you can achieve -that while still using the ``AUTO`` strategy, by configuring what it -defaults to. +If you are using `doctrine/dbal` 4, we now recommend using ``IDENTITY`` +for PostgreSQL, and you can achieve that while still using the ``AUTO`` +strategy, by configuring what it defaults to. .. code-block:: php diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index c0aee937650..dcddcf3194a 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -34,6 +34,7 @@ use function in_array; use function is_a; use function is_subclass_of; +use function method_exists; use function str_contains; use function strlen; use function strtolower; @@ -616,7 +617,14 @@ private function determineIdGeneratorStrategy(AbstractPlatform $platform): int } } - foreach (self::NON_IDENTITY_DEFAULT_STRATEGY as $platformFamily => $strategy) { + $nonIdentityDefaultStrategy = self::NON_IDENTITY_DEFAULT_STRATEGY; + + // DBAL 3 + if (method_exists($platform, 'getIdentitySequenceName')) { + $nonIdentityDefaultStrategy[Platforms\PostgreSQLPlatform::class] = ClassMetadata::GENERATOR_TYPE_SEQUENCE; + } + + foreach ($nonIdentityDefaultStrategy as $platformFamily => $strategy) { if (is_a($platform, $platformFamily)) { return $strategy; } diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php index 752ad559b18..545c44d28cc 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php @@ -9,6 +9,7 @@ use Doctrine\DBAL\Driver; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManagerInterface; @@ -139,6 +140,38 @@ public function testRelyingOnLegacyIdGenerationDefaultsIsOKIfItResultsInTheCurre $cmf->getMetadataFor($cm->name); } + public function testPostgresSticksWithSequencesWhenDbal3IsUsed(): void + { + if (! method_exists(AbstractPlatform::class, 'getIdentitySequenceName')) { + self::markTestSkipped('This test requires DBAL 3'); + } + + $cm = $this->createValidClassMetadata(); + $cm->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO); + $cmf = $this->setUpCmfForPlatform(new PostgreSQLPlatform()); + $cmf->setMetadataForClass($cm->name, $cm); + + $metadata = $cmf->getMetadataFor($cm->name); + + self::assertSame(ClassMetadata::GENERATOR_TYPE_SEQUENCE, $metadata->generatorType); + } + + public function testPostgresSwitchesToIdentityColumnsWhenDbal4IsUsed(): void + { + if (method_exists(AbstractPlatform::class, 'getIdentitySequenceName')) { + self::markTestSkipped('This test requires DBAL 4'); + } + + $cm = $this->createValidClassMetadata(); + $cm->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO); + $cmf = $this->setUpCmfForPlatform(new PostgreSQLPlatform()); + $cmf->setMetadataForClass($cm->name, $cm); + + $metadata = $cmf->getMetadataFor($cm->name); + + self::assertSame(ClassMetadata::GENERATOR_TYPE_IDENTITY, $metadata->generatorType); + } + public function testGetMetadataForThrowsExceptionOnUnknownCustomGeneratorClass(): void { $cm1 = $this->createValidClassMetadata();