Skip to content

Commit 4e633c7

Browse files
authored
Compatibility with ORM 3 and DBAL 4 (#1363)
1 parent 8022851 commit 4e633c7

File tree

15 files changed

+139
-128
lines changed

15 files changed

+139
-128
lines changed

.github/workflows/continuous-integration.yml

+11-1
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,19 @@ jobs:
3434
- "8.2"
3535
dependencies:
3636
- "highest"
37+
stability:
38+
- "default"
3739
include:
3840
- dependencies: "lowest"
41+
stability: "default"
3942
php-version: "8.1"
43+
- dependencies: "highest"
44+
stability: "dev"
45+
php-version: "8.2"
4046

4147
steps:
4248
- name: "Checkout"
43-
uses: "actions/checkout@v3"
49+
uses: "actions/checkout@v4"
4450

4551
- name: "Install PHP"
4652
uses: "shivammathur/setup-php@v2"
@@ -53,6 +59,10 @@ jobs:
5359
- name: "Download box"
5460
run: "./download-box.sh"
5561

62+
- name: "Allow dev dependencies"
63+
if: "matrix.stability == 'dev'"
64+
run: "composer config minimum-stability dev"
65+
5666
- name: "Install dependencies with Composer"
5767
uses: "ramsey/composer-install@v2"
5868
with:

composer.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"require": {
2727
"php": "^8.1",
2828
"composer-runtime-api": "^2",
29-
"doctrine/dbal": "^3.5.1",
29+
"doctrine/dbal": "^3.5.1 || ^4",
3030
"doctrine/deprecations": "^0.5.3 || ^1",
3131
"doctrine/event-manager": "^1.2 || ^2.0",
3232
"psr/log": "^1.1.3 || ^2 || ^3",
@@ -37,7 +37,7 @@
3737
"require-dev": {
3838
"ext-pdo_sqlite": "*",
3939
"doctrine/coding-standard": "^12",
40-
"doctrine/orm": "^2.13",
40+
"doctrine/orm": "^2.13 || ^3",
4141
"doctrine/persistence": "^2 || ^3",
4242
"doctrine/sql-formatter": "^1.0",
4343
"phpstan/phpstan": "^1.10",
@@ -51,7 +51,7 @@
5151
"symfony/yaml": "^5.4 || ^6.0 || ^7.0"
5252
},
5353
"conflict": {
54-
"doctrine/orm": "<2.12"
54+
"doctrine/orm": "<2.12 || >=4"
5555
},
5656
"suggest": {
5757
"doctrine/sql-formatter": "Allows to generate formatted SQL with the diff command.",

lib/Doctrine/Migrations/DependencyFactory.php

+24-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Doctrine\Migrations;
66

7+
use Doctrine\Common\EventManager;
78
use Doctrine\DBAL\Connection;
89
use Doctrine\Migrations\Configuration\Configuration;
910
use Doctrine\Migrations\Configuration\Connection\ConnectionLoader;
@@ -51,6 +52,7 @@
5152

5253
use function array_key_exists;
5354
use function call_user_func;
55+
use function method_exists;
5456
use function preg_quote;
5557
use function sprintf;
5658

@@ -67,16 +69,12 @@ class DependencyFactory
6769
/** @var object[]|callable[] */
6870
private array $dependencies = [];
6971

70-
private Connection|null $connection = null;
71-
72+
private Connection|null $connection = null;
7273
private EntityManagerInterface|null $em = null;
73-
74-
private bool $frozen = false;
75-
74+
private EventManager|null $eventManager = null;
75+
private bool $frozen = false;
7676
private ConfigurationLoader $configurationLoader;
77-
7877
private ConnectionLoader $connectionLoader;
79-
8078
private EntityManagerLoader|null $emLoader = null;
8179

8280
/** @var callable[] */
@@ -193,7 +191,7 @@ public function getEventDispatcher(): EventDispatcher
193191
{
194192
return $this->getDependency(EventDispatcher::class, fn (): EventDispatcher => new EventDispatcher(
195193
$this->getConnection(),
196-
$this->getConnection()->getEventManager(),
194+
$this->getEventManager(),
197195
));
198196
}
199197

@@ -446,4 +444,22 @@ public function setDefinition(string $id, callable $service): void
446444
$this->assertNotFrozen();
447445
$this->factories[$id] = $service;
448446
}
447+
448+
private function getEventManager(): EventManager
449+
{
450+
if ($this->eventManager !== null) {
451+
return $this->eventManager;
452+
}
453+
454+
if ($this->hasEntityManager()) {
455+
return $this->eventManager = $this->getEntityManager()->getEventManager();
456+
}
457+
458+
if (method_exists(Connection::class, 'getEventManager')) {
459+
// DBAL < 4
460+
return $this->eventManager = $this->getConnection()->getEventManager();
461+
}
462+
463+
return $this->eventManager = new EventManager();
464+
}
449465
}

lib/Doctrine/Migrations/Metadata/Storage/TableMetadataStorage.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public function complete(ExecutionResult $result): void
132132
$this->configuration->getExecutionTimeColumnName() => $result->getTime() === null ? null : (int) round($result->getTime() * 1000),
133133
], [
134134
Types::STRING,
135-
Types::DATETIME_MUTABLE,
135+
Types::DATETIME_IMMUTABLE,
136136
Types::INTEGER,
137137
]);
138138
}

lib/Doctrine/Migrations/SchemaDumper.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public function dump(
8080
$up[] = $upCode;
8181
}
8282

83-
$downSql = [$this->platform->getDropTableSQL($table)];
83+
$downSql = [$this->platform->getDropTableSQL($table->getQuotedName($this->platform))];
8484

8585
$downCode = $this->migrationSqlGenerator->generate(
8686
$downSql,

phpstan.neon.dist

+13
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,26 @@ parameters:
4242
"""
4343
count: 1
4444
path: tests/Doctrine/Migrations/Tests/Tools/Console/legacy-config-orm/cli-config.php
45+
-
46+
message: """
47+
#^Fetching class constant class of deprecated class Doctrine\\\\ORM\\\\Tools\\\\Console\\\\Helper\\\\EntityManagerHelper\\:
48+
This class will be removed in ORM 3\\.0 without replacement\\.$#
49+
"""
50+
count: 1
51+
path: tests/Doctrine/Migrations/Tests/Tools/Console/ConsoleRunnerTest.php
4552

4653
# TODO: deprecate using the connection event manager and expose
4754
# our own event manager instead.
4855
-
4956
message: '~^Call to deprecated method getEventManager\(\) of class Doctrine\\DBAL\\Connection\.$~'
5057
path: lib/Doctrine/Migrations/DependencyFactory.php
5158

59+
# DBAL 4 forward compatibility
60+
- '~^Call to function method_exists\(\) with ''Doctrine\\\\DBAL\\\\Connection'' and ''getEventManager'' will always evaluate to true\.$~'
61+
- '~^Class Doctrine\\DBAL\\Platforms\\SQLitePlatform not found\.$~'
62+
- '~^Instantiated class Doctrine\\DBAL\\Platforms\\SQLitePlatform not found\.$~'
63+
- '~^Access to constant class on an unknown class Doctrine\\DBAL\\Platforms\\SQLitePlatform\.$~'
64+
- '~expects Doctrine\\DBAL\\Platforms\\AbstractPlatform, Doctrine\\DBAL\\Platforms\\SQLitePlatform given\.$~'
5265
symfony:
5366
console_application_loader: tests/Doctrine/Migrations/Tests/doctrine-migrations-phpstan-app.php
5467
includes:

tests/Doctrine/Migrations/Tests/Configuration/Connection/ConnectionLoaderTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Doctrine\Migrations\Tests\Configuration\Connection;
66

77
use Doctrine\DBAL\Connection;
8-
use Doctrine\DBAL\Platforms\SqlitePlatform;
8+
use Doctrine\DBAL\Platforms\SQLitePlatform;
99
use Doctrine\Migrations\Configuration\Connection\ConfigurationFile;
1010
use Doctrine\Migrations\Configuration\Connection\Exception\FileNotFound;
1111
use Doctrine\Migrations\Configuration\Connection\Exception\InvalidConfiguration;
@@ -39,15 +39,15 @@ public function testArrayConnectionConfigurationLoader(): void
3939
$loader = new ConfigurationFile(__DIR__ . '/_files/sqlite-connection.php');
4040
$conn = $loader->getConnection();
4141

42-
self::assertInstanceOf(SqlitePlatform::class, $conn->getDatabasePlatform());
42+
self::assertInstanceOf(SQLitePlatform::class, $conn->getDatabasePlatform());
4343
}
4444

4545
public function testArrayConnectionConfigurationLoaderWithConnectionInstance(): void
4646
{
4747
$loader = new ConfigurationFile(__DIR__ . '/_files/sqlite-connection-instance.php');
4848
$conn = $loader->getConnection();
4949

50-
self::assertInstanceOf(SqlitePlatform::class, $conn->getDatabasePlatform());
50+
self::assertInstanceOf(SQLitePlatform::class, $conn->getDatabasePlatform());
5151
}
5252

5353
public function testArrayConnectionConfigurationLoaderInvalid(): void

tests/Doctrine/Migrations/Tests/Configuration/EntityManager/EntityManagerTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Doctrine\Migrations\Tests\Configuration\EntityManager;
66

7-
use Doctrine\DBAL\Platforms\SqlitePlatform;
7+
use Doctrine\DBAL\Platforms\SQLitePlatform;
88
use Doctrine\Migrations\Configuration\EntityManager\ConfigurationFile;
99
use Doctrine\Migrations\Configuration\EntityManager\Exception\FileNotFound;
1010
use Doctrine\Migrations\Configuration\EntityManager\Exception\InvalidConfiguration;
@@ -39,15 +39,15 @@ public function testArrayEntityManagerConfigurationLoader(): void
3939
$loader = new ConfigurationFile(__DIR__ . '/_files/em-loader.php');
4040
$em = $loader->getEntityManager();
4141

42-
self::assertInstanceOf(SqlitePlatform::class, $em->getConnection()->getDatabasePlatform());
42+
self::assertInstanceOf(SQLitePlatform::class, $em->getConnection()->getDatabasePlatform());
4343
}
4444

4545
public function testArrayEntityManagerConfigurationLoaderWithEntityManagerInstance(): void
4646
{
4747
$loader = new ConfigurationFile(__DIR__ . '/_files/migrations-em.php');
4848
$em = $loader->getEntityManager();
4949

50-
self::assertInstanceOf(SqlitePlatform::class, $em->getConnection()->getDatabasePlatform());
50+
self::assertInstanceOf(SQLitePlatform::class, $em->getConnection()->getDatabasePlatform());
5151
}
5252

5353
public function testArrayEntityManagerConfigurationLoaderInvalid(): void

tests/Doctrine/Migrations/Tests/Event/Listeners/AutoCommitListenerTest.php

+2-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Doctrine\Migrations\Tests\Event\Listeners;
66

77
use Doctrine\DBAL\Connection;
8-
use Doctrine\DBAL\Driver\Connection as DriverConnection;
98
use Doctrine\Migrations\Event\Listeners\AutoCommitListener;
109
use Doctrine\Migrations\Event\MigrationsEventArgs;
1110
use Doctrine\Migrations\Metadata\MigrationPlanList;
@@ -16,9 +15,7 @@
1615

1716
class AutoCommitListenerTest extends MigrationTestCase
1817
{
19-
/** @var Connection&MockObject */
20-
private Connection $conn;
21-
18+
private Connection&MockObject $conn;
2219
private AutoCommitListener $listener;
2320

2421
public function testListenerDoesNothingDuringADryRun(): void
@@ -51,10 +48,7 @@ public function testListenerDoesFinalCommitWhenAutoCommitIsOff(): void
5148

5249
protected function setUp(): void
5350
{
54-
$this->conn = $this->createMock(Connection::class);
55-
$driverConnection = self::createStub(DriverConnection::class);
56-
$this->conn->method('getWrappedConnection')->willReturn($driverConnection);
57-
51+
$this->conn = $this->createMock(Connection::class);
5852
$this->listener = new AutoCommitListener();
5953
}
6054

tests/Doctrine/Migrations/Tests/Generator/DiffGeneratorTest.php

+29-47
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,17 @@
2020

2121
class DiffGeneratorTest extends TestCase
2222
{
23-
/** @var DBALConfiguration&MockObject */
24-
private DBALConfiguration $dbalConfiguration;
23+
private DBALConfiguration&MockObject $dbalConfiguration;
2524

2625
/** @var AbstractSchemaManager<AbstractPlatform>&MockObject */
27-
private AbstractSchemaManager $schemaManager;
28-
29-
/** @var SchemaProvider&MockObject */
30-
private SchemaProvider $schemaProvider;
31-
32-
/** @var AbstractPlatform&MockObject */
33-
private AbstractPlatform $platform;
34-
35-
/** @var Generator&MockObject */
36-
private Generator $migrationGenerator;
37-
38-
/** @var SqlGenerator&MockObject */
39-
private SqlGenerator $migrationSqlGenerator;
26+
private AbstractSchemaManager&MockObject $schemaManager;
4027

28+
private SchemaProvider&MockObject $schemaProvider;
29+
private AbstractPlatform&MockObject $platform;
30+
private Generator&MockObject $migrationGenerator;
31+
private SqlGenerator&MockObject $migrationSqlGenerator;
4132
private DiffGenerator $migrationDiffGenerator;
42-
43-
/** @var SchemaProvider&MockObject */
44-
private SchemaProvider $emptySchemaProvider;
33+
private SchemaProvider&MockObject $emptySchemaProvider;
4534

4635
public function testGenerate(): void
4736
{
@@ -89,7 +78,7 @@ public function testGenerate(): void
8978

9079
$toSchema->expects(self::exactly(2))
9180
->method('dropTable')
92-
->willReturnOnConsecutiveCalls('schema.table_name2', 'schema.table_name3');
81+
->willReturnSelf();
9382

9483
$schemaDiff = self::createStub(SchemaDiff::class);
9584

@@ -102,19 +91,7 @@ public function testGenerate(): void
10291
return ['UPDATE table SET value = 1'];
10392
});
10493

105-
// regular mocks cannot be used here, because the method is static
106-
$comparator = new class extends Comparator {
107-
public static SchemaDiff $schemaDiff;
108-
109-
public static function compareSchemas(
110-
Schema $fromSchema,
111-
Schema $toSchema,
112-
): SchemaDiff {
113-
return self::$schemaDiff;
114-
}
115-
};
116-
117-
$comparator::$schemaDiff = $schemaDiff;
94+
$comparator = $this->mockComparator($schemaDiff);
11895

11996
$this->schemaManager->expects(self::once())
12097
->method('createComparator')
@@ -151,10 +128,10 @@ public function testGenerateFromEmptySchema(): void
151128

152129
$this->dbalConfiguration->expects(self::once())
153130
->method('getSchemaAssetsFilter')
154-
->willReturn(null);
131+
->willReturn(static fn () => true);
155132

156-
$toSchema->expects(self::never())
157-
->method('getTables');
133+
$toSchema->method('getTables')
134+
->willReturn([new Table('table_name')]);
158135

159136
$this->emptySchemaProvider->expects(self::once())
160137
->method('createSchema')
@@ -181,18 +158,7 @@ public function testGenerateFromEmptySchema(): void
181158
});
182159

183160
// regular mocks cannot be used here, because the method is static
184-
$comparator = new class extends Comparator {
185-
public static SchemaDiff $schemaDiff;
186-
187-
public static function compareSchemas(
188-
Schema $fromSchema,
189-
Schema $toSchema,
190-
): SchemaDiff {
191-
return self::$schemaDiff;
192-
}
193-
};
194-
195-
$comparator::$schemaDiff = $schemaDiff;
161+
$comparator = $this->mockComparator($schemaDiff);
196162

197163
$this->schemaManager->expects(self::once())
198164
->method('createComparator')
@@ -233,4 +199,20 @@ protected function setUp(): void
233199
$this->emptySchemaProvider,
234200
);
235201
}
202+
203+
private function mockComparator(SchemaDiff $schemaDiff): Comparator
204+
{
205+
$comparator = new class (self::createStub(AbstractPlatform::class)) extends Comparator {
206+
public static SchemaDiff $schemaDiff;
207+
208+
public function compareSchemas(Schema $oldSchema, Schema $newSchema): SchemaDiff
209+
{
210+
return self::$schemaDiff;
211+
}
212+
};
213+
214+
$comparator::$schemaDiff = $schemaDiff;
215+
216+
return $comparator;
217+
}
236218
}

0 commit comments

Comments
 (0)