Skip to content

Commit a5a1696

Browse files
committed
Fixed schema comparison attempting to remove double foreign keys.
1 parent 2319596 commit a5a1696

File tree

3 files changed

+238
-6
lines changed

3 files changed

+238
-6
lines changed

.vscode/launch.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
8+
{
9+
"name": "Listen for Xdebug",
10+
"type": "php",
11+
"request": "launch",
12+
"port": 9003
13+
},
14+
{
15+
"name": "Launch currently open script",
16+
"type": "php",
17+
"request": "launch",
18+
"program": "${file}",
19+
"cwd": "${fileDirname}",
20+
"port": 0,
21+
"runtimeArgs": [
22+
"-dxdebug.start_with_request=yes"
23+
],
24+
"env": {
25+
"XDEBUG_MODE": "debug,develop",
26+
"XDEBUG_CONFIG": "client_port=${port}"
27+
}
28+
},
29+
{
30+
"name": "Launch Built-in web server",
31+
"type": "php",
32+
"request": "launch",
33+
"runtimeArgs": [
34+
"-dxdebug.mode=debug",
35+
"-dxdebug.start_with_request=yes",
36+
"-S",
37+
"localhost:0"
38+
],
39+
"program": "",
40+
"cwd": "${workspaceRoot}",
41+
"port": 9003,
42+
"serverReadyAction": {
43+
"pattern": "Development Server \\(http://localhost:([0-9]+)\\) started",
44+
"uriFormat": "http://localhost:%s",
45+
"action": "openExternally"
46+
}
47+
}
48+
]
49+
}

src/Schema/Comparator.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,14 +275,17 @@ public function compareTables(Table $oldTable, Table $newTable): TableDiff
275275
foreach ($newForeignKeys as $newKey => $newForeignKey) {
276276
if ($this->diffForeignKey($oldForeignKey, $newForeignKey) === false) {
277277
unset($oldForeignKeys[$oldKey], $newForeignKeys[$newKey]);
278-
} else {
279-
if (strtolower($oldForeignKey->getName()) === strtolower($newForeignKey->getName())) {
280-
$droppedForeignKeys[$oldKey] = $oldForeignKey;
281-
$addedForeignKeys[$newKey] = $newForeignKey;
278+
continue 2;
279+
}
282280

283-
unset($oldForeignKeys[$oldKey], $newForeignKeys[$newKey]);
284-
}
281+
if (strtolower($oldForeignKey->getName()) !== strtolower($newForeignKey->getName())) {
282+
continue;
285283
}
284+
285+
$droppedForeignKeys[$oldKey] = $oldForeignKey;
286+
$addedForeignKeys[$newKey] = $newForeignKey;
287+
288+
unset($oldForeignKeys[$oldKey], $newForeignKeys[$newKey]);
286289
}
287290
}
288291

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Tests\Functional\Schema;
6+
7+
use Doctrine\DBAL\Platforms\OraclePlatform;
8+
use Doctrine\DBAL\Schema\AbstractSchemaManager;
9+
use Doctrine\DBAL\Schema\Column;
10+
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
11+
use Doctrine\DBAL\Schema\PrimaryKeyConstraint;
12+
use Doctrine\DBAL\Schema\Table;
13+
use Doctrine\DBAL\Tests\FunctionalTestCase;
14+
use Doctrine\DBAL\Types\Types;
15+
16+
class DoubleForeignKeyConstraintTest extends FunctionalTestCase
17+
{
18+
private AbstractSchemaManager $schemaManager;
19+
20+
protected function setUp(): void
21+
{
22+
$this->schemaManager = $this->connection->createSchemaManager();
23+
}
24+
25+
public function testDoubleForeignKeyConstraint(): void
26+
{
27+
if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
28+
self::markTestSkipped('Oracle does not allow multiple FKs with the same columns.');
29+
}
30+
31+
$articles = Table::editor()
32+
->setUnquotedName('articles')
33+
->setColumns(
34+
Column::editor()
35+
->setUnquotedName('id')
36+
->setTypeName(Types::INTEGER)
37+
->create(),
38+
)
39+
->setPrimaryKeyConstraint(
40+
PrimaryKeyConstraint::editor()
41+
->setUnquotedColumnNames('id')
42+
->create(),
43+
)
44+
->create();
45+
46+
$orders = Table::editor()
47+
->setUnquotedName('orders')
48+
->setColumns(
49+
Column::editor()
50+
->setUnquotedName('id')
51+
->setTypeName(Types::INTEGER)
52+
->create(),
53+
Column::editor()
54+
->setUnquotedName('article_id')
55+
->setTypeName(Types::INTEGER)
56+
->create(),
57+
)
58+
->setForeignKeyConstraints(
59+
ForeignKeyConstraint::editor()
60+
->setUnquotedName('articles_fk')
61+
->setUnquotedReferencingColumnNames('article_id')
62+
->setUnquotedReferencedTableName('articles')
63+
->setUnquotedReferencedColumnNames('id')
64+
->create(),
65+
ForeignKeyConstraint::editor()
66+
->setUnquotedName('articles_fk_2')
67+
->setUnquotedReferencingColumnNames('article_id')
68+
->setUnquotedReferencedTableName('articles')
69+
->setUnquotedReferencedColumnNames('id')
70+
->create(),
71+
)
72+
->create();
73+
74+
$this->dropTableIfExists('orders');
75+
$this->dropTableIfExists('articles');
76+
77+
$this->connection->createSchemaManager()
78+
->createTable($articles);
79+
$this->connection->createSchemaManager()
80+
->createTable($orders);
81+
82+
$ordersActual = $this->schemaManager->introspectTable('orders');
83+
84+
self::assertTrue(
85+
$this->schemaManager->createComparator()
86+
->compareTables($ordersActual, $orders)
87+
->isEmpty(),
88+
);
89+
}
90+
91+
public function testDoubleForeignKeyConstraintComparedToSingle(): void
92+
{
93+
if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
94+
self::markTestSkipped('Oracle does not allow multiple FKs with the same columns.');
95+
}
96+
97+
$articles = Table::editor()
98+
->setUnquotedName('articles')
99+
->setColumns(
100+
Column::editor()
101+
->setUnquotedName('id')
102+
->setTypeName(Types::INTEGER)
103+
->create(),
104+
)
105+
->setPrimaryKeyConstraint(
106+
PrimaryKeyConstraint::editor()
107+
->setUnquotedColumnNames('id')
108+
->create(),
109+
)
110+
->create();
111+
112+
$orders = Table::editor()
113+
->setUnquotedName('orders')
114+
->setColumns(
115+
Column::editor()
116+
->setUnquotedName('id')
117+
->setTypeName(Types::INTEGER)
118+
->create(),
119+
Column::editor()
120+
->setUnquotedName('article_id')
121+
->setTypeName(Types::INTEGER)
122+
->create(),
123+
)
124+
->setForeignKeyConstraints(
125+
ForeignKeyConstraint::editor()
126+
->setUnquotedName('articles_fk')
127+
->setUnquotedReferencingColumnNames('article_id')
128+
->setUnquotedReferencedTableName('articles')
129+
->setUnquotedReferencedColumnNames('id')
130+
->create(),
131+
ForeignKeyConstraint::editor()
132+
->setUnquotedName('articles_fk_2')
133+
->setUnquotedReferencingColumnNames('article_id')
134+
->setUnquotedReferencedTableName('articles')
135+
->setUnquotedReferencedColumnNames('id')
136+
->create(),
137+
)
138+
->create();
139+
140+
$ordersCompare = Table::editor()
141+
->setUnquotedName('orders')
142+
->setColumns(
143+
Column::editor()
144+
->setUnquotedName('id')
145+
->setTypeName(Types::INTEGER)
146+
->create(),
147+
Column::editor()
148+
->setUnquotedName('article_id')
149+
->setTypeName(Types::INTEGER)
150+
->create(),
151+
)
152+
->setForeignKeyConstraints(
153+
ForeignKeyConstraint::editor()
154+
->setUnquotedName('articles_fk')
155+
->setUnquotedReferencingColumnNames('article_id')
156+
->setUnquotedReferencedTableName('articles')
157+
->setUnquotedReferencedColumnNames('id')
158+
->create(),
159+
)
160+
->create();
161+
162+
$this->dropTableIfExists('orders');
163+
$this->dropTableIfExists('articles');
164+
165+
$this->connection->createSchemaManager()
166+
->createTable($articles);
167+
$this->connection->createSchemaManager()
168+
->createTable($orders);
169+
170+
$ordersActual = $this->schemaManager->introspectTable('orders');
171+
172+
$diff = $this->schemaManager->createComparator()
173+
->compareTables($ordersActual, $ordersCompare);
174+
175+
self::assertFalse($diff->isEmpty());
176+
self::assertCount(0, $diff->getAddedForeignKeys());
177+
self::assertCount(1, $diff->getDroppedForeignKeys());
178+
self::assertSame('articles_fk_2', $diff->getDroppedForeignKeys()[0]->getName());
179+
}
180+
}

0 commit comments

Comments
 (0)