Skip to content

Commit fcf7bd1

Browse files
valkarsValentin Karnauhov
andauthored
Add support for doctrine/dbal 4 (#652)
Co-authored-by: Valentin Karnauhov <v.karnauhov@itteco.lv>
1 parent a931c42 commit fcf7bd1

11 files changed

Lines changed: 238 additions & 58 deletions

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"require": {
1212
"php": "^8.1",
1313
"doctrine/collections": "^1.8 || ^2.0",
14-
"doctrine/dbal": "^3.6",
14+
"doctrine/dbal": "^3.6 || ^4.0",
1515
"doctrine/event-manager": "^1.2 || ^2.0",
1616
"doctrine/orm": "^2.14 || ^3.0",
1717
"doctrine/persistence": "^3.0",

src/AuditReader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ public function find($className, $id, $revision, array $options = [])
297297
$allDiscrValues = array_flip($classMetadata->discriminatorMap);
298298
$queriedDiscrValues = [$this->em->getConnection()->quote($classMetadata->discriminatorValue)];
299299
foreach ($classMetadata->subClasses as $subclassName) {
300-
$queriedDiscrValues[] = $this->em->getConnection()->quote($allDiscrValues[$subclassName]);
300+
$queriedDiscrValues[] = $this->em->getConnection()->quote((string) $allDiscrValues[$subclassName]);
301301
}
302302

303303
$whereSQL .= \sprintf(

src/EventListener/CreateSchemaListener.php

Lines changed: 150 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@
1515

1616
use Doctrine\Common\EventSubscriber;
1717
use Doctrine\DBAL\Schema\Column;
18+
use Doctrine\DBAL\Schema\Name\Identifier;
19+
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
20+
use Doctrine\DBAL\Schema\PrimaryKeyConstraint;
1821
use Doctrine\DBAL\Schema\Schema;
1922
use Doctrine\DBAL\Schema\Table;
23+
use Doctrine\DBAL\Types\StringType;
2024
use Doctrine\DBAL\Types\Type;
2125
use Doctrine\DBAL\Types\Types;
2226
use Doctrine\ORM\Mapping\ClassMetadata;
@@ -26,6 +30,7 @@
2630
use SimpleThings\EntityAudit\AuditConfiguration;
2731
use SimpleThings\EntityAudit\AuditManager;
2832
use SimpleThings\EntityAudit\Metadata\MetadataFactory;
33+
use SimpleThings\EntityAudit\Utils\DbalCompatibilityTrait;
2934
use SimpleThings\EntityAudit\Utils\ORMCompatibilityTrait;
3035

3136
/**
@@ -36,6 +41,7 @@
3641
*/
3742
class CreateSchemaListener implements EventSubscriber
3843
{
44+
use DbalCompatibilityTrait;
3945
use ORMCompatibilityTrait;
4046

4147
private AuditConfiguration $config;
@@ -95,25 +101,47 @@ public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs)
95101
$revisionsTable = $this->createRevisionsTable($schema);
96102

97103
$entityTable = $eventArgs->getClassTable();
98-
$revisionTable = $schema->createTable(
99-
$this->config->getTablePrefix().$entityTable->getName().$this->config->getTableSuffix()
100-
);
104+
if ($this->isDbal4_3()) {
105+
$tableName = $this->config->getTablePrefix().$entityTable->getObjectName()->toString().$this->config->getTableSuffix();
106+
} else {
107+
/** @psalm-suppress InternalMethod */
108+
$tableName = $this->config->getTablePrefix().$entityTable->getName().$this->config->getTableSuffix(); // @phpstan-ignore-line
109+
}
110+
$revisionTable = $schema->createTable($tableName);
101111

102112
foreach ($entityTable->getColumns() as $column) {
103113
$this->addColumnToTable($column, $revisionTable);
104114
}
105115
$revisionTable->addColumn($this->config->getRevisionFieldName(), $this->config->getRevisionIdFieldType());
106116
$revisionTable->addColumn($this->config->getRevisionTypeFieldName(), Types::STRING, ['length' => 4]);
107117
if (!\in_array($cm->inheritanceType, [ClassMetadata::INHERITANCE_TYPE_NONE, ClassMetadata::INHERITANCE_TYPE_JOINED, ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE], true)) {
108-
throw new \Exception(\sprintf('Inheritance type "%s" is not yet supported', $cm->inheritanceType));
118+
throw new \RuntimeException(\sprintf('Inheritance type "%s" is not yet supported', $cm->inheritanceType));
109119
}
110120

111-
$primaryKey = $entityTable->getPrimaryKey();
112-
\assert(null !== $primaryKey);
113-
$pkColumns = $primaryKey->getColumns();
114-
$pkColumns[] = $this->config->getRevisionFieldName();
115-
$revisionTable->setPrimaryKey($pkColumns);
116-
$revIndexName = $this->config->getRevisionFieldName().'_'.md5($revisionTable->getName()).'_idx';
121+
if ($this->isDbal4_3()) {
122+
$primaryKey = $entityTable->getPrimaryKeyConstraint();
123+
\assert(null !== $primaryKey);
124+
$pkColumns = $primaryKey->getColumnNames();
125+
/** @psalm-suppress ArgumentTypeCoercion */
126+
$pkColumns[] = new UnqualifiedName(Identifier::unquoted($this->config->getRevisionFieldName())); // @phpstan-ignore-line
127+
$editor = PrimaryKeyConstraint::editor()->setColumnNames(...$pkColumns)->setIsClustered($primaryKey->isClustered());
128+
$revisionTable->addPrimaryKeyConstraint($editor->create());
129+
} else {
130+
/** @psalm-suppress DeprecatedMethod */
131+
$primaryKey = $entityTable->getPrimaryKey();
132+
\assert(null !== $primaryKey);
133+
/** @psalm-suppress DeprecatedMethod */
134+
$pkColumns = $primaryKey->getColumns();
135+
$pkColumns[] = $this->config->getRevisionFieldName();
136+
/** @psalm-suppress DeprecatedMethod */
137+
$revisionTable->setPrimaryKey($pkColumns);
138+
}
139+
if ($this->isDbal4_3()) {
140+
$revIndexName = $this->config->getRevisionFieldName().'_'.md5($revisionTable->getObjectName()->toString()).'_idx';
141+
} else {
142+
/** @psalm-suppress InternalMethod */
143+
$revIndexName = $this->config->getRevisionFieldName().'_'.md5($revisionTable->getName()).'_idx'; // @phpstan-ignore-line
144+
}
117145
$revisionTable->addIndex([$this->config->getRevisionFieldName()], $revIndexName);
118146

119147
foreach ($cm->associationMappings as $associationMapping) {
@@ -143,25 +171,61 @@ public function postGenerateSchema(GenerateSchemaEventArgs $eventArgs): void
143171

144172
private function createForeignKeys(Table $relatedTable, Table $revisionsTable): void
145173
{
146-
$revisionForeignKeyName = $this->config->getRevisionFieldName().'_'.md5($relatedTable->getName()).'_fk';
147-
$primaryKey = $revisionsTable->getPrimaryKey();
148-
\assert(null !== $primaryKey);
149-
150-
$relatedTable->addForeignKeyConstraint(
151-
$revisionsTable,
152-
[$this->config->getRevisionFieldName()],
153-
$primaryKey->getColumns(),
154-
[],
155-
$revisionForeignKeyName
156-
);
174+
if ($this->isDbal4_3()) {
175+
$revisionForeignKeyName = $this->config->getRevisionFieldName().'_'.md5($relatedTable->getObjectName()->toString()).'_fk';
176+
$primaryKey = $revisionsTable->getPrimaryKeyConstraint();
177+
\assert(null !== $primaryKey);
178+
$relatedTable->addForeignKeyConstraint(
179+
$revisionsTable->getObjectName()->toString(),
180+
[$this->config->getRevisionFieldName()],
181+
array_map(static fn (UnqualifiedName $name) => $name->toString(), $primaryKey->getColumnNames()),
182+
[],
183+
$revisionForeignKeyName
184+
);
185+
} elseif ($this->isDbal4()) {
186+
/** @psalm-suppress InternalMethod */
187+
$revisionForeignKeyName = $this->config->getRevisionFieldName().'_'.md5($relatedTable->getName()).'_fk'; // @phpstan-ignore-line
188+
/** @psalm-suppress DeprecatedMethod */
189+
$primaryKey = $revisionsTable->getPrimaryKey();
190+
\assert(null !== $primaryKey);
191+
/** @psalm-suppress InternalMethod */
192+
/** @psalm-suppress DeprecatedMethod */
193+
$relatedTable->addForeignKeyConstraint(
194+
$revisionsTable->getName(), // @phpstan-ignore-line
195+
[$this->config->getRevisionFieldName()],
196+
$primaryKey->getColumns(),
197+
[],
198+
$revisionForeignKeyName
199+
);
200+
} else {
201+
/** @psalm-suppress InternalMethod */
202+
$revisionForeignKeyName = $this->config->getRevisionFieldName().'_'.md5($relatedTable->getName()).'_fk'; // @phpstan-ignore-line
203+
/** @psalm-suppress DeprecatedMethod */
204+
$primaryKey = $revisionsTable->getPrimaryKey();
205+
\assert(null !== $primaryKey);
206+
/** @psalm-suppress DeprecatedMethod */
207+
/** @psalm-suppress InvalidArgument */
208+
$relatedTable->addForeignKeyConstraint(
209+
$revisionsTable, // @phpstan-ignore-line doctrine/dbal 3 support for old addForeignKeyConstraint() signature
210+
[$this->config->getRevisionFieldName()],
211+
$primaryKey->getColumns(),
212+
[],
213+
$revisionForeignKeyName
214+
);
215+
}
157216
}
158217

159218
/**
160219
* Copies $column to another table. All its options are copied but notnull and autoincrement which are set to false.
161220
*/
162221
private function addColumnToTable(Column $column, Table $targetTable): void
163222
{
164-
$columnName = $column->getName();
223+
if ($this->isDbal4_3()) {
224+
$columnName = $column->getObjectName()->toString();
225+
} else {
226+
/** @psalm-suppress InternalMethod */
227+
$columnName = $column->getName(); // @phpstan-ignore-line
228+
}
165229

166230
$targetTable->addColumn(
167231
$columnName,
@@ -175,9 +239,16 @@ private function addColumnToTable(Column $column, Table $targetTable): void
175239
$targetColumn->setUnsigned($column->getUnsigned());
176240
$targetColumn->setFixed($column->getFixed());
177241
$targetColumn->setDefault($column->getDefault());
178-
$targetColumn->setColumnDefinition($column->getColumnDefinition());
242+
if ('' !== $column->getColumnDefinition()) {
243+
$targetColumn->setColumnDefinition($column->getColumnDefinition());
244+
}
179245
$targetColumn->setComment($column->getComment());
180-
$targetColumn->setPlatformOptions($column->getPlatformOptions());
246+
if ($this->isDbal4_3()) {
247+
$targetColumn->setPlatformOptions(['charset' => $column->getCharset(), 'collation' => $column->getCollation()]);
248+
} else {
249+
/** @psalm-suppress DeprecatedMethod */
250+
$targetColumn->setPlatformOptions($column->getPlatformOptions());
251+
}
181252

182253
$targetColumn->setNotnull(false);
183254
$targetColumn->setAutoincrement(false);
@@ -196,41 +267,79 @@ private function createRevisionsTable(Schema $schema): Table
196267
'autoincrement' => true,
197268
]);
198269
$revisionsTable->addColumn('timestamp', Types::DATETIME_MUTABLE);
199-
$revisionsTable->addColumn('username', Types::STRING)->setNotnull(false);
200-
$revisionsTable->setPrimaryKey(['id']);
270+
$revisionsTable->addColumn('username', Types::STRING, ['length' => 255])->setNotnull(false);
271+
if ($this->isDbal4_3()) {
272+
$id = new UnqualifiedName(Identifier::unquoted('id'));
273+
$editor = PrimaryKeyConstraint::editor()->setColumnNames($id)->setIsClustered(true);
274+
$revisionsTable->addPrimaryKeyConstraint($editor->create());
275+
} else {
276+
/** @psalm-suppress DeprecatedMethod */
277+
$revisionsTable->setPrimaryKey(['id']);
278+
}
201279

202280
return $revisionsTable;
203281
}
204282

205283
private function createRevisionJoinTableForJoinTable(Schema $schema, string $joinTableName): void
206284
{
207285
$joinTable = $schema->getTable($joinTableName);
208-
$revisionJoinTableName = $this->config->getTablePrefix().$joinTable->getName().$this->config->getTableSuffix();
286+
if ($this->isDbal4_3()) {
287+
$revisionJoinTableName = $this->config->getTablePrefix().$joinTable->getObjectName()->toString().$this->config->getTableSuffix();
288+
} else {
289+
/** @psalm-suppress InternalMethod */
290+
$revisionJoinTableName = $this->config->getTablePrefix().$joinTable->getName().$this->config->getTableSuffix(); // @phpstan-ignore-line
291+
}
209292

210293
if ($schema->hasTable($revisionJoinTableName)) {
211294
return;
212295
}
213296

214297
$typeRegistry = Type::getTypeRegistry();
215-
$revisionJoinTable = $schema->createTable(
216-
$this->config->getTablePrefix().$joinTable->getName().$this->config->getTableSuffix()
217-
);
298+
if ($this->isDbal4_3()) {
299+
$tableName = $this->config->getTablePrefix().$joinTable->getObjectName()->toString().$this->config->getTableSuffix();
300+
} else {
301+
/** @psalm-suppress InternalMethod */
302+
$tableName = $this->config->getTablePrefix().$joinTable->getName().$this->config->getTableSuffix(); // @phpstan-ignore-line
303+
}
304+
$revisionJoinTable = $schema->createTable($tableName);
305+
/** @var Column $column */
218306
foreach ($joinTable->getColumns() as $column) {
219-
/* @var Column $column */
220-
$revisionJoinTable->addColumn(
221-
$column->getName(),
222-
$typeRegistry->lookupName($column->getType()),
223-
['notnull' => false, 'autoincrement' => false]
224-
);
307+
$options = ['notnull' => false, 'autoincrement' => false];
308+
if ($column->getType() instanceof StringType) {
309+
$options['length'] = $column->getLength();
310+
}
311+
if ($this->isDbal4_3()) {
312+
$revisionJoinTable->addColumn($column->getObjectName()->toString(), $typeRegistry->lookupName($column->getType()), $options);
313+
} else {
314+
/** @psalm-suppress InternalMethod */
315+
$revisionJoinTable->addColumn($column->getName(), $typeRegistry->lookupName($column->getType()), $options); // @phpstan-ignore-line
316+
}
225317
}
226318
$revisionJoinTable->addColumn($this->config->getRevisionFieldName(), $this->config->getRevisionIdFieldType());
227319
$revisionJoinTable->addColumn($this->config->getRevisionTypeFieldName(), 'string', ['length' => 4]);
228320

229-
$pk = $joinTable->getPrimaryKey();
230-
$pkColumns = null !== $pk ? $pk->getColumns() : [];
231-
$pkColumns[] = $this->config->getRevisionFieldName();
232-
$revisionJoinTable->setPrimaryKey($pkColumns);
233-
$revIndexName = $this->config->getRevisionFieldName().'_'.md5($revisionJoinTable->getName()).'_idx';
321+
if ($this->isDbal4_3()) {
322+
$pk = $joinTable->getPrimaryKeyConstraint();
323+
$pkColumns = null !== $pk ? $pk->getColumnNames() : [];
324+
/** @psalm-suppress ArgumentTypeCoercion */
325+
$pkColumns[] = new UnqualifiedName(Identifier::unquoted($this->config->getRevisionFieldName())); // @phpstan-ignore-line
326+
$editor = PrimaryKeyConstraint::editor()->setColumnNames(...$pkColumns)->setIsClustered(!(null !== $pk) || $pk->isClustered());
327+
$revisionJoinTable->addPrimaryKeyConstraint($editor->create());
328+
} else {
329+
/** @psalm-suppress DeprecatedMethod */
330+
$pk = $joinTable->getPrimaryKey();
331+
/** @psalm-suppress DeprecatedMethod */
332+
$pkColumns = null !== $pk ? $pk->getColumns() : [];
333+
$pkColumns[] = $this->config->getRevisionFieldName();
334+
/** @psalm-suppress DeprecatedMethod */
335+
$revisionJoinTable->setPrimaryKey($pkColumns);
336+
}
337+
if ($this->isDbal4_3()) {
338+
$revIndexName = $this->config->getRevisionFieldName().'_'.md5($revisionJoinTable->getObjectName()->toString()).'_idx';
339+
} else {
340+
/** @psalm-suppress InternalMethod */
341+
$revIndexName = $this->config->getRevisionFieldName().'_'.md5($revisionJoinTable->getName()).'_idx'; // @phpstan-ignore-line
342+
}
234343
$revisionJoinTable->addIndex([$this->config->getRevisionFieldName()], $revIndexName);
235344
}
236345
}

0 commit comments

Comments
 (0)