Skip to content

Commit

Permalink
Merge pull request #11044 from greg0ire/identity-on-dbal4
Browse files Browse the repository at this point in the history
Recommend SEQUENCE until doctrine/dbal 4 is released
  • Loading branch information
greg0ire authored Nov 7, 2023
2 parents be62f72 + 300cffb commit 0e95838
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 61 deletions.
17 changes: 9 additions & 8 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,30 @@ It will be a full-fledged class, no longer extending

When the `AUTO` identifier generation strategy was introduced, the best
strategy at the time was selected for each database platform.
A lot of time has passed since then, and support for better strategies has been
added.
A lot of time has passed since then, and with ORM 3.0.0 and DBAL 4.0.0, support
for better strategies will be added.

Because of that, it is now deprecated to rely on the historical defaults when
they differ from what we recommend now.
they differ from what we will be recommended in the future.

Instead, you should pick a strategy for each database platform you use, and it
will be used when using `AUTO`. As of now, only PostgreSQL is affected by this.
It is recommended that PostgreSQL user configure their new applications to use
`IDENTITY`:

It is recommended that PostgreSQL users configure their existing and new
applications to use `SEQUENCE` until `doctrine/dbal` 4.0.0 is released:

```php
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\ORM\Configuration;

assert($configuration instanceof Configuration);
$configuration->setIdentityGenerationPreferences([
PostgreSQLPlatform::CLASS => ClassMetadata::GENERATOR_TYPE_IDENTITY,
PostgreSQLPlatform::CLASS => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
]);
```

If migrating an existing application is too costly, the deprecation can be
addressed by configuring `SEQUENCE` as the default strategy.
When DBAL 4 is released, `AUTO` will result in `IDENTITY`, and the above
configuration should be removed to migrate to it.

## Deprecate `EntityManagerInterface::getPartialReference()`

Expand Down
14 changes: 0 additions & 14 deletions docs/en/reference/basic-mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -427,20 +427,6 @@ 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.

.. code-block:: php
<?php
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\ORM\Configuration;
$config = new Configuration();
$config->setIdentityGenerationPreferences([
PostgreSQLPlatform::class => ClassMetadata::GENERATOR_TYPE_IDENTITY,
]);

.. _identifier-generation-strategies:

Expand Down
37 changes: 9 additions & 28 deletions lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

use function assert;
use function class_exists;
use function constant;
use function count;
use function end;
use function explode;
Expand Down Expand Up @@ -74,26 +73,10 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
/** @var mixed[] */
private $embeddablesActiveNesting = [];

private const LEGACY_DEFAULTS_FOR_ID_GENERATION = [
'Doctrine\DBAL\Platforms\MySqlPlatform' => ClassMetadata::GENERATOR_TYPE_IDENTITY,
private const NON_IDENTITY_DEFAULT_STRATEGY = [
'Doctrine\DBAL\Platforms\PostgreSqlPlatform' => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
Platforms\DB2Platform::class => ClassMetadata::GENERATOR_TYPE_IDENTITY,
Platforms\MySQLPlatform::class => ClassMetadata::GENERATOR_TYPE_IDENTITY,
Platforms\OraclePlatform::class => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
Platforms\PostgreSQLPlatform::class => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
Platforms\SQLServerPlatform::class => ClassMetadata::GENERATOR_TYPE_IDENTITY,
Platforms\SqlitePlatform::class => ClassMetadata::GENERATOR_TYPE_IDENTITY,
];

private const RECOMMENDED_STRATEGY = [
'Doctrine\DBAL\Platforms\MySqlPlatform' => 'IDENTITY',
'Doctrine\DBAL\Platforms\PostgreSqlPlatform' => 'IDENTITY',
Platforms\DB2Platform::class => 'IDENTITY',
Platforms\MySQLPlatform::class => 'IDENTITY',
Platforms\OraclePlatform::class => 'SEQUENCE',
Platforms\PostgreSQLPlatform::class => 'IDENTITY',
Platforms\SQLServerPlatform::class => 'IDENTITY',
Platforms\SqlitePlatform::class => 'IDENTITY',
];

/** @return void */
Expand Down Expand Up @@ -657,7 +640,7 @@ private function completeIdGeneratorMapping(ClassMetadataInfo $class): void
'https://github.com/doctrine/orm/issues/8850',
<<<'DEPRECATION'
Context: Loading metadata for class %s
Problem: Using the IDENTITY generator strategy with platform "%s" is deprecated and will not be possible in Doctrine ORM 3.0.
Problem: Using identity columns emulated with a sequence is deprecated and will not be possible in Doctrine ORM 3.0.
Solution: Use the SEQUENCE generator strategy instead.
DEPRECATION
,
Expand Down Expand Up @@ -762,27 +745,25 @@ private function determineIdGeneratorStrategy(AbstractPlatform $platform): int
}
}

foreach (self::LEGACY_DEFAULTS_FOR_ID_GENERATION as $platformFamily => $strategy) {
foreach (self::NON_IDENTITY_DEFAULT_STRATEGY as $platformFamily => $strategy) {
if (is_a($platform, $platformFamily)) {
$recommendedStrategyName = self::RECOMMENDED_STRATEGY[$platformFamily];
if ($strategy !== constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $recommendedStrategyName)) {
if ($platform instanceof Platforms\PostgreSQLPlatform || is_a($platform, 'Doctrine\DBAL\Platforms\PostgreSqlPlatform')) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/issues/8893',
<<<'DEPRECATION'
Relying on non-optimal defaults for ID generation is deprecated.
Relying on non-optimal defaults for ID generation is deprecated, and IDENTITY
results in SERIAL, which is not recommended.
Instead, configure identifier generation strategies explicitly through
configuration.
We currently recommend "%s" for "%s", so you should use
We currently recommend "SEQUENCE" for "%s", so you should use
$configuration->setIdentityGenerationPreferences([
"%s" => ClassMetadata::GENERATOR_TYPE_%s,
"%s" => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
]);
DEPRECATION
,
$recommendedStrategyName,
$platformFamily,
$platformFamily,
$recommendedStrategyName
$platformFamily
);
}

Expand Down
1 change: 1 addition & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@
<code>$class</code>
<code>$class</code>
<code>$platformFamily</code>
<code><![CDATA['Doctrine\DBAL\Platforms\PostgreSqlPlatform']]></code>
<code><![CDATA[new $definition['class']()]]></code>
</ArgumentTypeCoercion>
<DeprecatedClass>
Expand Down
22 changes: 11 additions & 11 deletions tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,37 +170,37 @@ private function setUpCmfForPlatform(AbstractPlatform $platform, array $preferen
return $cmf;
}

public function testRelyingOnLegacyIdGenerationDefaultsIsDeprecatedIfItResultsInASuboptimalDefault(): void
public function testRelyingOnLegacyIdGenerationDefaultsIsOKIfItResultsInTheCurrentlyRecommendedStrategyBeingUsed(): void
{
$cm = $this->createValidClassMetadata();
$cm->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);

$cmf = $this->setUpCmfForPlatform(new PostgreSQLPlatform());
$cmf = $this->setUpCmfForPlatform(new OraclePlatform());
$cmf->setMetadataForClass($cm->name, $cm);

$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issues/8893');
$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issues/8893');
$cmf->getMetadataFor($cm->name);
}

public function testSpecifyingIdGenerationStrategyThroughConfigurationFixesTheDeprecation(): void
public function testRelyingOnLegacyIdGenerationDefaultsIsDeprecatedIfItResultsInADefaultThatWillChange(): void
{
$cm = $this->createValidClassMetadata();
$cm->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);

$cmf = $this->setUpCmfForPlatform(new PostgreSQLPlatform(), [
PostgreSQLPlatform::class => ClassMetadata::GENERATOR_TYPE_IDENTITY,
]);
$cmf = $this->setUpCmfForPlatform(new PostgreSQLPlatform());
$cmf->setMetadataForClass($cm->name, $cm);

$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issues/8893');
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issues/8893');
$cmf->getMetadataFor($cm->name);
}

public function testRelyingOnLegacyIdGenerationDefaultsIsOKIfItResultsInTheCurrentlyRecommendedStrategyBeingUsed(): void
public function testSpecifyingIdGenerationStrategyThroughConfigurationFixesTheDeprecation(): void
{
$cm = $this->createValidClassMetadata();
$cm->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
$cmf = $this->setUpCmfForPlatform(new OraclePlatform());

$cmf = $this->setUpCmfForPlatform(new PostgreSQLPlatform(), [
PostgreSQLPlatform::class => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
]);
$cmf->setMetadataForClass($cm->name, $cm);

$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issues/8893');
Expand Down

0 comments on commit 0e95838

Please sign in to comment.