Skip to content

Commit 73f194b

Browse files
committed
Migrate to schema and column editor APIs
1 parent 2f396b8 commit 73f194b

2 files changed

Lines changed: 154 additions & 17 deletions

File tree

phpstan-dbal3.neon

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,36 @@ parameters:
164164
-
165165
message: '~inferType.*never returns~'
166166
path: src/Query/ParameterTypeInferer.php
167+
168+
# DBAL 4/5 Schema Editor API compatibility
169+
-
170+
message: '~^Class Doctrine\\DBAL\\Schema\\Table constructor invoked with 7 parameters, 1-6 required\.$~'
171+
path: src/Tools/SchemaTool.php
172+
173+
-
174+
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\SchemaConfig::toTableConfiguration\(\)\.$~'
175+
path: src/Tools/SchemaTool.php
176+
177+
-
178+
message: '~^Call to method setAutoincrement\(\) on an unknown class Doctrine\\DBAL\\Schema\\ColumnEditor\.$~'
179+
path: src/Tools/SchemaTool.php
180+
181+
-
182+
message: '~^Parameter \$column of anonymous function has invalid type Doctrine\\DBAL\\Schema\\ColumnEditor\.$~'
183+
path: src/Tools/SchemaTool.php
184+
185+
-
186+
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\Table::edit\(\)\.$~'
187+
path: src/Tools/SchemaTool.php
188+
189+
-
190+
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\Table::modifyColumnByUnquotedName\(\)\.$~'
191+
path: src/Tools/SchemaTool.php
192+
193+
-
194+
message: '~^Instantiated class Doctrine\\DBAL\\Schema\\ColumnEditor not found\.$~'
195+
path: src/Tools/SchemaTool.php
196+
197+
-
198+
message: '~^Unknown parameter \$configuration in call to Doctrine\\DBAL\\Schema\\Table constructor\.$~'
199+
path: src/Tools/SchemaTool.php

src/Tools/SchemaTool.php

Lines changed: 121 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Doctrine\DBAL\Platforms\AbstractPlatform;
99
use Doctrine\DBAL\Schema\AbstractAsset;
1010
use Doctrine\DBAL\Schema\AbstractSchemaManager;
11+
use Doctrine\DBAL\Schema\ColumnEditor;
1112
use Doctrine\DBAL\Schema\ComparatorConfig;
1213
use Doctrine\DBAL\Schema\DefaultExpression;
1314
use Doctrine\DBAL\Schema\DefaultExpression\CurrentDate;
@@ -21,6 +22,7 @@
2122
use Doctrine\DBAL\Schema\NamedObject;
2223
use Doctrine\DBAL\Schema\PrimaryKeyConstraint;
2324
use Doctrine\DBAL\Schema\Schema;
25+
use Doctrine\DBAL\Schema\SchemaConfig;
2426
use Doctrine\DBAL\Schema\Table;
2527
use Doctrine\DBAL\Types\Types;
2628
use Doctrine\Deprecations\Deprecation;
@@ -204,11 +206,36 @@ public function getSchemaFromMetadata(array $classes): Schema
204206
continue;
205207
}
206208

207-
$table = $schema->createTable($this->quoteStrategy->getTableName($class, $this->platform));
209+
$tableName = $this->quoteStrategy->getTableName($class, $this->platform);
210+
211+
// @phpstan-ignore function.impossibleType (Using unreleased Schema::edit() API)
212+
if (method_exists(Schema::class, 'edit')) {
213+
$table = new Table(
214+
name: $tableName,
215+
configuration: $metadataSchemaConfig->toTableConfiguration(),
216+
);
217+
// Add default table options (charset, collation, engine, etc.)
218+
foreach ($metadataSchemaConfig->getDefaultTableOptions() as $option => $value) {
219+
$table->addOption($option, $value);
220+
}
221+
} else {
222+
$table = $schema->createTable($tableName);
223+
}
208224

209225
if ($class->isInheritanceTypeSingleTable()) {
226+
// For new schema API: collect join tables to add after this entity table
227+
$joinTablesToAdd = [];
228+
210229
$this->gatherColumns($class, $table);
211-
$this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);
230+
$this->gatherRelationsSql(
231+
$class,
232+
$table,
233+
$schema,
234+
$addedFks,
235+
$blacklistedFks,
236+
$metadataSchemaConfig,
237+
$joinTablesToAdd,
238+
);
212239

213240
// Add the discriminator column
214241
$this->addDiscriminatorColumnDefinition($class, $table);
@@ -222,18 +249,37 @@ public function getSchemaFromMetadata(array $classes): Schema
222249
foreach ($class->subClasses as $subClassName) {
223250
$subClass = $this->em->getClassMetadata($subClassName);
224251
$this->gatherColumns($subClass, $table);
225-
$this->gatherRelationsSql($subClass, $table, $schema, $addedFks, $blacklistedFks);
252+
$this->gatherRelationsSql(
253+
$subClass,
254+
$table,
255+
$schema,
256+
$addedFks,
257+
$blacklistedFks,
258+
$metadataSchemaConfig,
259+
$joinTablesToAdd,
260+
);
226261
$processedClasses[$subClassName] = true;
227262
}
228263
} elseif ($class->isInheritanceTypeJoined()) {
264+
// For new schema API: collect join tables to add after this entity table
265+
$joinTablesToAdd = [];
266+
229267
// Add all non-inherited fields as columns
230268
foreach ($class->fieldMappings as $fieldName => $mapping) {
231269
if (! isset($mapping->inherited)) {
232270
$this->gatherColumn($class, $mapping, $table);
233271
}
234272
}
235273

236-
$this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);
274+
$this->gatherRelationsSql(
275+
$class,
276+
$table,
277+
$schema,
278+
$addedFks,
279+
$blacklistedFks,
280+
$metadataSchemaConfig,
281+
$joinTablesToAdd,
282+
);
237283

238284
// Add the discriminator column only to the root table
239285
if ($class->name === $class->rootEntityName) {
@@ -253,7 +299,17 @@ public function getSchemaFromMetadata(array $classes): Schema
253299
$this->platform,
254300
);
255301
// TODO: This seems rather hackish, can we optimize it?
256-
$table->getColumn($columnName)->setAutoincrement(false);
302+
// @phpstan-ignore function.impossibleType (Using unreleased Schema::edit() API for version detection)
303+
if (method_exists(Schema::class, 'edit')) {
304+
// New API: modify column using table editor (creates new table object)
305+
// This is safe because we'll add the table to schema later after all modifications
306+
$table = $table->edit()->modifyColumnByUnquotedName(
307+
$columnName,
308+
static fn (ColumnEditor $column) => $column->setAutoincrement(false),
309+
)->create();
310+
} else {
311+
$table->getColumn($columnName)->setAutoincrement(false);
312+
}
257313

258314
$pkColumns[] = $columnName;
259315
$inheritedKeyColumns[] = $columnName;
@@ -305,8 +361,19 @@ public function getSchemaFromMetadata(array $classes): Schema
305361
}
306362
}
307363
} else {
364+
// For new schema API: collect join tables to add after this entity table
365+
$joinTablesToAdd = [];
366+
308367
$this->gatherColumns($class, $table);
309-
$this->gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);
368+
$this->gatherRelationsSql(
369+
$class,
370+
$table,
371+
$schema,
372+
$addedFks,
373+
$blacklistedFks,
374+
$metadataSchemaConfig,
375+
$joinTablesToAdd,
376+
);
310377
}
311378

312379
$pkColumns = [];
@@ -377,6 +444,22 @@ public function getSchemaFromMetadata(array $classes): Schema
377444

378445
$processedClasses[$class->name] = true;
379446

447+
// Add the fully populated table to the schema
448+
// @phpstan-ignore function.impossibleType (Using unreleased Schema::edit() API)
449+
if (method_exists(Schema::class, 'edit')) {
450+
// @phpstan-ignore method.notFound (Using unreleased Schema::edit() API)
451+
$schemaEditor = $schema->edit();
452+
$schemaEditor->addTable($table);
453+
454+
// Add any join tables collected during relation processing
455+
// This ensures join tables appear right after their owning entity table
456+
foreach ($joinTablesToAdd as $joinTable) {
457+
$schemaEditor->addTable($joinTable);
458+
}
459+
460+
$schema = $schemaEditor->create();
461+
}
462+
380463
if ($class->isIdGeneratorSequence() && $class->name === $class->rootEntityName) {
381464
$seqDef = $class->sequenceGeneratorDefinition;
382465
$quotedName = $this->quoteStrategy->getSequenceName($seqDef, $class, $this->platform);
@@ -405,12 +488,12 @@ public function getSchemaFromMetadata(array $classes): Schema
405488
$newTable = $tableEventArgs->getClassTable();
406489

407490
// @phpstan-ignore method.notFound (Using unreleased Schema::edit() API)
408-
$schemaEditor = $schema->edit();
409-
$schemaEditor->dropTable($originalTableName);
410-
$schemaEditor->addTable($newTable);
491+
$schema = $schema->edit()
492+
->dropTable($originalTableName)
493+
->addTable($newTable)
494+
->create();
411495

412-
$schema = $schemaEditor->create();
413-
$table = $newTable;
496+
$table = $newTable;
414497
}
415498
}
416499
}
@@ -614,15 +697,18 @@ private function gatherColumn(
614697
* fkOptions: array{onDelete?: string, deferrable?: bool, deferred?: bool}
615698
* }> $addedFks
616699
* @phpstan-param array<string, bool> $blacklistedFks
700+
* @phpstan-param list<Table> $joinTablesToAdd
617701
*
618702
* @throws NotSupported
619703
*/
620704
private function gatherRelationsSql(
621705
ClassMetadata $class,
622706
Table $table,
623-
Schema $schema,
707+
Schema &$schema,
624708
array &$addedFks,
625709
array &$blacklistedFks,
710+
SchemaConfig $schemaConfig,
711+
array &$joinTablesToAdd,
626712
): void {
627713
foreach ($class->associationMappings as $id => $mapping) {
628714
if (isset($mapping->inherited) && ! in_array($id, $class->identifier, true)) {
@@ -647,12 +733,25 @@ private function gatherRelationsSql(
647733
// create join table
648734
$joinTable = $mapping->joinTable;
649735

650-
$theJoinTable = $schema->createTable(
651-
$this->quoteStrategy->getJoinTableName($mapping, $foreignClass, $this->platform),
652-
);
736+
$tableName = $this->quoteStrategy->getJoinTableName($mapping, $foreignClass, $this->platform);
653737

654-
foreach ($joinTable->options as $key => $val) {
655-
$theJoinTable->addOption($key, $val);
738+
// Create the join table object
739+
// @phpstan-ignore function.impossibleType (Using unreleased Schema::edit() API)
740+
if (method_exists(Schema::class, 'edit')) {
741+
$theJoinTable = new Table(
742+
name: $tableName,
743+
options: $joinTable->options,
744+
configuration: $schemaConfig->toTableConfiguration(),
745+
);
746+
// Add default table options (charset, collation, engine, etc.)
747+
foreach ($schemaConfig->getDefaultTableOptions() as $option => $value) {
748+
$theJoinTable->addOption($option, $value);
749+
}
750+
} else {
751+
$theJoinTable = $schema->createTable($tableName);
752+
foreach ($joinTable->options as $key => $val) {
753+
$theJoinTable->addOption($key, $val);
754+
}
656755
}
657756

658757
$primaryKeyColumns = [];
@@ -680,6 +779,11 @@ private function gatherRelationsSql(
680779
);
681780

682781
self::addPrimaryKeyConstraint($theJoinTable, $primaryKeyColumns);
782+
783+
// @phpstan-ignore function.impossibleType (Using unreleased Schema::edit() API)
784+
if (method_exists(Schema::class, 'edit')) {
785+
$joinTablesToAdd[] = $theJoinTable;
786+
}
683787
}
684788
}
685789
}

0 commit comments

Comments
 (0)