Skip to content

Commit

Permalink
Dynamically resolve AUTO to SEQUENCE or IDENTITY
Browse files Browse the repository at this point in the history
With DBAL 3.x, IDENTITY results in SERIAL.
With DBAL 4.x, it results in the standard GENERATED BY DEFAULT AS IDENTITY.
  • Loading branch information
greg0ire committed Nov 5, 2023
1 parent 73288bc commit 41b31bc
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 9 deletions.
10 changes: 5 additions & 5 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions docs/en/reference/basic-mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
33 changes: 33 additions & 0 deletions tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 41b31bc

Please sign in to comment.