@@ -202,6 +202,7 @@ public function getSchemaFromMetadata(array $classes): Schema
202202 $ blacklistedFks = [];
203203
204204 foreach ($ classes as $ class ) {
205+ $ columnNames = [];
205206 if ($ this ->processingNotRequired ($ class , $ processedClasses )) {
206207 continue ;
207208 }
@@ -223,10 +224,11 @@ public function getSchemaFromMetadata(array $classes): Schema
223224 // For new schema API: collect join tables to add after this entity table
224225 $ joinTablesToAdd = [];
225226
226- $ this ->gatherColumns ($ class , $ table );
227+ $ this ->gatherColumns ($ class , $ table, $ columnNames );
227228 $ this ->gatherRelationsSql (
228229 $ class ,
229230 $ table ,
231+ $ columnNames ,
230232 $ schema ,
231233 $ addedFks ,
232234 $ blacklistedFks ,
@@ -245,10 +247,11 @@ public function getSchemaFromMetadata(array $classes): Schema
245247
246248 foreach ($ class ->subClasses as $ subClassName ) {
247249 $ subClass = $ this ->em ->getClassMetadata ($ subClassName );
248- $ this ->gatherColumns ($ subClass , $ table );
250+ $ this ->gatherColumns ($ subClass , $ table, $ columnNames );
249251 $ this ->gatherRelationsSql (
250252 $ subClass ,
251253 $ table ,
254+ $ columnNames ,
252255 $ schema ,
253256 $ addedFks ,
254257 $ blacklistedFks ,
@@ -264,13 +267,14 @@ public function getSchemaFromMetadata(array $classes): Schema
264267 // Add all non-inherited fields as columns
265268 foreach ($ class ->fieldMappings as $ fieldName => $ mapping ) {
266269 if (! isset ($ mapping ->inherited )) {
267- $ this ->gatherColumn ($ class , $ mapping , $ table );
270+ $ this ->gatherColumn ($ class , $ mapping , $ table, $ columnNames );
268271 }
269272 }
270273
271274 $ this ->gatherRelationsSql (
272275 $ class ,
273276 $ table ,
277+ $ columnNames ,
274278 $ schema ,
275279 $ addedFks ,
276280 $ blacklistedFks ,
@@ -289,7 +293,7 @@ public function getSchemaFromMetadata(array $classes): Schema
289293 foreach ($ class ->identifier as $ identifierField ) {
290294 if (isset ($ class ->fieldMappings [$ identifierField ]->inherited )) {
291295 $ idMapping = $ class ->fieldMappings [$ identifierField ];
292- $ this ->gatherColumn ($ class , $ idMapping , $ table );
296+ $ this ->gatherColumn ($ class , $ idMapping , $ table, $ columnNames );
293297 $ columnName = $ this ->quoteStrategy ->getColumnName (
294298 $ identifierField ,
295299 $ class ,
@@ -361,10 +365,11 @@ public function getSchemaFromMetadata(array $classes): Schema
361365 // For new schema API: collect join tables to add after this entity table
362366 $ joinTablesToAdd = [];
363367
364- $ this ->gatherColumns ($ class , $ table );
368+ $ this ->gatherColumns ($ class , $ table, $ columnNames );
365369 $ this ->gatherRelationsSql (
366370 $ class ,
367371 $ table ,
372+ $ columnNames ,
368373 $ schema ,
369374 $ addedFks ,
370375 $ blacklistedFks ,
@@ -540,28 +545,32 @@ private function addDiscriminatorColumnDefinition(ClassMetadata $class, Table $t
540545 /**
541546 * Gathers the column definitions as required by the DBAL of all field mappings
542547 * found in the given class.
548+ *
549+ * @param array<string, true> $columnNames
543550 */
544- private function gatherColumns (ClassMetadata $ class , Table $ table ): void
551+ private function gatherColumns (ClassMetadata $ class , Table $ table, array & $ columnNames ): void
545552 {
546553 foreach ($ class ->fieldMappings as $ mapping ) {
547554 if ($ class ->isInheritanceTypeSingleTable () && isset ($ mapping ->inherited )) {
548555 continue ;
549556 }
550557
551- $ this ->gatherColumn ($ class , $ mapping , $ table );
558+ $ this ->gatherColumn ($ class , $ mapping , $ table, $ columnNames );
552559 }
553560 }
554561
555562 /**
556563 * Creates a column definition as required by the DBAL from an ORM field mapping definition.
557564 *
558- * @param ClassMetadata $class The class that owns the field mapping.
565+ * @param ClassMetadata $class The class that owns the field mapping.
566+ * @param array<string, true> $columnNames The list of column names already added to the table.
559567 * @phpstan-param FieldMapping $mapping The field mapping.
560568 */
561569 private function gatherColumn (
562570 ClassMetadata $ class ,
563571 FieldMapping $ mapping ,
564572 Table $ table ,
573+ array &$ columnNames ,
565574 ): void {
566575 $ columnName = $ this ->quoteStrategy ->getColumnName ($ mapping ->fieldName , $ class , $ this ->platform );
567576 $ columnType = $ mapping ->type ;
@@ -667,11 +676,11 @@ private function gatherColumn(
667676 $ options ['autoincrement ' ] = false ;
668677 }
669678
670- if ($ table ->hasColumn ($ columnName )) {
671- // required in some inheritance scenarios
679+ if (isset ($ columnNames [$ columnName ])) {
672680 $ table ->modifyColumn ($ columnName , $ options );
673681 } else {
674682 $ table ->addColumn ($ columnName , $ columnType , $ options );
683+ $ columnNames [$ columnName ] = true ;
675684 }
676685
677686 $ isUnique = $ mapping ->unique ?? false ;
@@ -689,6 +698,7 @@ private function gatherColumn(
689698 * Gathers the SQL for properly setting up the relations of the given class.
690699 * This includes the SQL for foreign key constraints and join tables.
691700 *
701+ * @param array<string, true> $columnNames
692702 * @phpstan-param array<string, array{
693703 * foreignTableName: string,
694704 * foreignColumns: list<string>,
@@ -702,6 +712,7 @@ private function gatherColumn(
702712 private function gatherRelationsSql (
703713 ClassMetadata $ class ,
704714 Table $ table ,
715+ array &$ columnNames ,
705716 Schema &$ schema ,
706717 array &$ addedFks ,
707718 array &$ blacklistedFks ,
@@ -721,6 +732,7 @@ private function gatherRelationsSql(
721732 $ this ->gatherRelationJoinColumns (
722733 $ mapping ->joinColumns ,
723734 $ table ,
735+ $ columnNames ,
724736 $ foreignClass ,
725737 $ mapping ,
726738 $ primaryKeyColumns ,
@@ -753,11 +765,13 @@ private function gatherRelationsSql(
753765 }
754766
755767 $ primaryKeyColumns = [];
768+ $ joinColumnNames = [];
756769
757770 // Build first FK constraint (relation table => source table)
758771 $ this ->gatherRelationJoinColumns (
759772 $ joinTable ->joinColumns ,
760773 $ theJoinTable ,
774+ $ joinColumnNames ,
761775 $ class ,
762776 $ mapping ,
763777 $ primaryKeyColumns ,
@@ -769,6 +783,7 @@ private function gatherRelationsSql(
769783 $ this ->gatherRelationJoinColumns (
770784 $ joinTable ->inverseJoinColumns ,
771785 $ theJoinTable ,
786+ $ joinColumnNames ,
772787 $ foreignClass ,
773788 $ mapping ,
774789 $ primaryKeyColumns ,
@@ -826,6 +841,7 @@ private function getDefiningClass(ClassMetadata $class, string $referencedColumn
826841 /**
827842 * Gathers columns and fk constraints that are required for one part of relationship.
828843 *
844+ * @param array<string, true> $columnNames
829845 * @phpstan-param list<JoinColumnMapping> $joinColumns
830846 * @phpstan-param list<string> $primaryKeyColumns
831847 * @phpstan-param array<string, array{
@@ -840,6 +856,7 @@ private function getDefiningClass(ClassMetadata $class, string $referencedColumn
840856 private function gatherRelationJoinColumns (
841857 array $ joinColumns ,
842858 Table $ theJoinTable ,
859+ array &$ columnNames ,
843860 ClassMetadata $ class ,
844861 AssociationMapping $ mapping ,
845862 array &$ primaryKeyColumns ,
@@ -878,7 +895,7 @@ private function gatherRelationJoinColumns(
878895 $ localColumns [] = $ quotedColumnName ;
879896 $ foreignColumns [] = $ quotedRefColumnName ;
880897
881- if (! $ theJoinTable -> hasColumn ( $ quotedColumnName )) {
898+ if (! isset ( $ columnNames [ $ quotedColumnName] )) {
882899 // Only add the column to the table if it does not exist already.
883900 // It might exist already if the foreign key is mapped into a regular
884901 // property as well.
@@ -911,6 +928,7 @@ private function gatherRelationJoinColumns(
911928 $ columnOptions = $ this ->gatherColumnOptions ($ joinColumn ) + $ columnOptions ;
912929
913930 $ theJoinTable ->addColumn ($ quotedColumnName , $ fieldMapping ->type , $ columnOptions );
931+ $ columnNames [$ quotedColumnName ] = true ;
914932 }
915933
916934 if (isset ($ joinColumn ->unique ) && $ joinColumn ->unique === true ) {
0 commit comments