1515
1616use Doctrine \Common \EventSubscriber ;
1717use Doctrine \DBAL \Schema \Column ;
18+ use Doctrine \DBAL \Schema \Name \Identifier ;
19+ use Doctrine \DBAL \Schema \Name \UnqualifiedName ;
20+ use Doctrine \DBAL \Schema \PrimaryKeyConstraint ;
1821use Doctrine \DBAL \Schema \Schema ;
1922use Doctrine \DBAL \Schema \Table ;
23+ use Doctrine \DBAL \Types \StringType ;
2024use Doctrine \DBAL \Types \Type ;
2125use Doctrine \DBAL \Types \Types ;
2226use Doctrine \ORM \Mapping \ClassMetadata ;
2630use SimpleThings \EntityAudit \AuditConfiguration ;
2731use SimpleThings \EntityAudit \AuditManager ;
2832use SimpleThings \EntityAudit \Metadata \MetadataFactory ;
33+ use SimpleThings \EntityAudit \Utils \DbalCompatibilityTrait ;
2934use SimpleThings \EntityAudit \Utils \ORMCompatibilityTrait ;
3035
3136/**
3641 */
3742class 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