Skip to content

Commit d2cf6b9

Browse files
Add support for extra SQL statements in table creation and dropping
1 parent 74a6637 commit d2cf6b9

File tree

4 files changed

+290
-0
lines changed

4 files changed

+290
-0
lines changed

src/Platforms/AbstractPlatform.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,20 @@ private function buildCreateTableSQL(Table $table, bool $createForeignKeys): arr
948948
}
949949
}
950950

951+
if ($createForeignKeys && $table->hasOption(Table::OPTION_EXTRA_CREATE_SQL)) {
952+
if (! is_array($table->getOption(Table::OPTION_EXTRA_CREATE_SQL))) {
953+
throw new InvalidArgumentException(sprintf('Table option "%s" must be an array', Table::OPTION_EXTRA_CREATE_SQL));
954+
}
955+
956+
foreach ($table->getOption(Table::OPTION_EXTRA_CREATE_SQL) as $extraSql) {
957+
if (! is_string($extraSql)) {
958+
throw new InvalidArgumentException(sprintf('Table option "%s" must be an array of strings', Table::OPTION_EXTRA_CREATE_SQL));
959+
}
960+
961+
$sql[] = $extraSql;
962+
}
963+
}
964+
951965
return $sql;
952966
}
953967

@@ -971,6 +985,28 @@ public function getCreateTablesSQL(array $tables): array
971985
$table->getQuotedName($this),
972986
);
973987
}
988+
989+
if (! $table->hasOption(Table::OPTION_EXTRA_CREATE_SQL)) {
990+
continue;
991+
}
992+
993+
if (! is_array($table->getOption(Table::OPTION_EXTRA_CREATE_SQL))) {
994+
throw new InvalidArgumentException(sprintf(
995+
'Table option "%s" must be an array',
996+
Table::OPTION_EXTRA_CREATE_SQL,
997+
));
998+
}
999+
1000+
foreach ($table->getOption(Table::OPTION_EXTRA_CREATE_SQL) as $extraSql) {
1001+
if (! is_string($extraSql)) {
1002+
throw new InvalidArgumentException(sprintf(
1003+
'Table option "%s" must be an array of strings',
1004+
Table::OPTION_EXTRA_CREATE_SQL,
1005+
));
1006+
}
1007+
1008+
$sql[] = $extraSql;
1009+
}
9741010
}
9751011

9761012
return $sql;
@@ -986,6 +1022,26 @@ public function getDropTablesSQL(array $tables): array
9861022
$sql = [];
9871023

9881024
foreach ($tables as $table) {
1025+
if ($table->hasOption(Table::OPTION_EXTRA_DROP_SQL)) {
1026+
if (! is_array($table->getOption(Table::OPTION_EXTRA_DROP_SQL))) {
1027+
throw new InvalidArgumentException(sprintf(
1028+
'Table option "%s" must be an array',
1029+
Table::OPTION_EXTRA_DROP_SQL,
1030+
));
1031+
}
1032+
1033+
foreach ($table->getOption(Table::OPTION_EXTRA_DROP_SQL) as $extraSql) {
1034+
if (! is_string($extraSql)) {
1035+
throw new InvalidArgumentException(sprintf(
1036+
'Table option "%s" must be an array of strings',
1037+
Table::OPTION_EXTRA_DROP_SQL,
1038+
));
1039+
}
1040+
1041+
$sql[] = $extraSql;
1042+
}
1043+
}
1044+
9891045
foreach ($table->getForeignKeys() as $foreignKey) {
9901046
$sql[] = $this->getDropForeignKeySQL(
9911047
$foreignKey->getQuotedName($this),

src/Platforms/SQLitePlatform.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
use function count;
3636
use function explode;
3737
use function implode;
38+
use function is_array;
39+
use function is_string;
3840
use function sprintf;
3941
use function str_replace;
4042
use function strpos;
@@ -593,6 +595,30 @@ public function getDropTablesSQL(array $tables): array
593595
{
594596
$sql = [];
595597

598+
foreach ($tables as $table) {
599+
if (! $table->hasOption(Table::OPTION_EXTRA_DROP_SQL)) {
600+
continue;
601+
}
602+
603+
if (! is_array($table->getOption(Table::OPTION_EXTRA_DROP_SQL))) {
604+
throw new InvalidArgumentException(sprintf(
605+
'Table option "%s" must be an array',
606+
Table::OPTION_EXTRA_DROP_SQL,
607+
));
608+
}
609+
610+
foreach ($table->getOption(Table::OPTION_EXTRA_DROP_SQL) as $extraSql) {
611+
if (! is_string($extraSql)) {
612+
throw new InvalidArgumentException(sprintf(
613+
'Table option "%s" must be an array of strings',
614+
Table::OPTION_EXTRA_DROP_SQL,
615+
));
616+
}
617+
618+
$sql[] = $extraSql;
619+
}
620+
}
621+
596622
foreach ($tables as $table) {
597623
$sql[] = $this->getDropTableSQL($table->getQuotedName($this));
598624
}

src/Schema/Table.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
*/
4444
class Table extends AbstractNamedObject
4545
{
46+
public const OPTION_EXTRA_CREATE_SQL = 'extra_create_sql';
47+
public const OPTION_EXTRA_DROP_SQL = 'extra_drop_sql';
48+
4649
/** @var Column[] */
4750
protected array $_columns = [];
4851

tests/Platforms/AbstractPlatformTestCase.php

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,4 +1279,209 @@ public static function getEnumDeclarationSQLWithInvalidValuesProvider(): array
12791279
"field 'values' is an empty array" => [['values' => []]],
12801280
];
12811281
}
1282+
1283+
public function testGetCreateTableSQLWithExtraCreateSQL(): void
1284+
{
1285+
$table = Table::editor()
1286+
->setUnquotedName('test')
1287+
->setColumns(
1288+
Column::editor()
1289+
->setUnquotedName('id')
1290+
->setTypeName(Types::INTEGER)
1291+
->setAutoincrement(true)
1292+
->create(),
1293+
)
1294+
->setPrimaryKeyConstraint(
1295+
PrimaryKeyConstraint::editor()
1296+
->setUnquotedColumnNames('id')
1297+
->create(),
1298+
)
1299+
->setOptions([
1300+
Table::OPTION_EXTRA_CREATE_SQL => [
1301+
'CREATE INDEX idx_test ON test (id)',
1302+
'CREATE VIEW test_view AS SELECT * FROM test',
1303+
],
1304+
])
1305+
->create();
1306+
1307+
$sql = $this->platform->getCreateTableSQL($table);
1308+
1309+
// Should contain the CREATE TABLE statement
1310+
self::assertNotEmpty($sql);
1311+
self::assertStringContainsString('CREATE TABLE', $sql[0]);
1312+
// Should contain the extra SQL statements
1313+
self::assertContains('CREATE INDEX idx_test ON test (id)', $sql);
1314+
self::assertContains('CREATE VIEW test_view AS SELECT * FROM test', $sql);
1315+
}
1316+
1317+
public function testGetCreateTableSQLWithExtraCreateSQLNonArrayThrowsException(): void
1318+
{
1319+
$table = Table::editor()
1320+
->setUnquotedName('test')
1321+
->setColumns(
1322+
Column::editor()
1323+
->setUnquotedName('id')
1324+
->setTypeName(Types::INTEGER)
1325+
->create(),
1326+
)
1327+
->setPrimaryKeyConstraint(
1328+
PrimaryKeyConstraint::editor()
1329+
->setUnquotedColumnNames('id')
1330+
->create(),
1331+
)
1332+
->setOptions([Table::OPTION_EXTRA_CREATE_SQL => 'not an array'])
1333+
->create();
1334+
1335+
$this->expectException(InvalidArgumentException::class);
1336+
$this->expectExceptionMessage(sprintf('Table option "%s" must be an array', Table::OPTION_EXTRA_CREATE_SQL));
1337+
1338+
$this->platform->getCreateTableSQL($table);
1339+
}
1340+
1341+
public function testGetCreateTablesSQLWithExtraCreateSQL(): void
1342+
{
1343+
$table1 = Table::editor()
1344+
->setUnquotedName('test1')
1345+
->setColumns(
1346+
Column::editor()
1347+
->setUnquotedName('id')
1348+
->setTypeName(Types::INTEGER)
1349+
->setAutoincrement(true)
1350+
->create(),
1351+
)
1352+
->setPrimaryKeyConstraint(
1353+
PrimaryKeyConstraint::editor()
1354+
->setUnquotedColumnNames('id')
1355+
->create(),
1356+
)
1357+
->setOptions([Table::OPTION_EXTRA_CREATE_SQL => ['CREATE INDEX idx_test1 ON test1 (id)']])
1358+
->create();
1359+
1360+
$table2 = Table::editor()
1361+
->setUnquotedName('test2')
1362+
->setColumns(
1363+
Column::editor()
1364+
->setUnquotedName('id')
1365+
->setTypeName(Types::INTEGER)
1366+
->setAutoincrement(true)
1367+
->create(),
1368+
)
1369+
->setPrimaryKeyConstraint(
1370+
PrimaryKeyConstraint::editor()
1371+
->setUnquotedColumnNames('id')
1372+
->create(),
1373+
)
1374+
->setOptions([Table::OPTION_EXTRA_CREATE_SQL => ['CREATE INDEX idx_test2 ON test2 (id)']])
1375+
->create();
1376+
1377+
$sql = $this->platform->getCreateTablesSQL([$table1, $table2]);
1378+
1379+
self::assertContains('CREATE INDEX idx_test1 ON test1 (id)', $sql);
1380+
self::assertContains('CREATE INDEX idx_test2 ON test2 (id)', $sql);
1381+
}
1382+
1383+
public function testGetCreateTablesSQLWithExtraCreateSQLNonArrayThrowsException(): void
1384+
{
1385+
$table = Table::editor()
1386+
->setUnquotedName('test')
1387+
->setColumns(
1388+
Column::editor()
1389+
->setUnquotedName('id')
1390+
->setTypeName(Types::INTEGER)
1391+
->create(),
1392+
)
1393+
->setPrimaryKeyConstraint(
1394+
PrimaryKeyConstraint::editor()
1395+
->setUnquotedColumnNames('id')
1396+
->create(),
1397+
)
1398+
->setOptions([Table::OPTION_EXTRA_CREATE_SQL => 'not an array'])
1399+
->create();
1400+
1401+
$this->expectException(InvalidArgumentException::class);
1402+
$this->expectExceptionMessage(sprintf('Table option "%s" must be an array', Table::OPTION_EXTRA_CREATE_SQL));
1403+
1404+
$this->platform->getCreateTablesSQL([$table]);
1405+
}
1406+
1407+
public function testGetDropTablesSQLWithExtraDropSQL(): void
1408+
{
1409+
$table1 = Table::editor()
1410+
->setUnquotedName('test1')
1411+
->setColumns(
1412+
Column::editor()
1413+
->setUnquotedName('id')
1414+
->setTypeName(Types::INTEGER)
1415+
->create(),
1416+
)
1417+
->setOptions([
1418+
Table::OPTION_EXTRA_DROP_SQL => [
1419+
'DROP VIEW IF EXISTS test1_view',
1420+
'DROP TRIGGER IF EXISTS test1_trigger',
1421+
],
1422+
])
1423+
->create();
1424+
1425+
$table2 = Table::editor()
1426+
->setUnquotedName('test2')
1427+
->setColumns(
1428+
Column::editor()
1429+
->setUnquotedName('id')
1430+
->setTypeName(Types::INTEGER)
1431+
->create(),
1432+
)
1433+
->setOptions([Table::OPTION_EXTRA_DROP_SQL => ['DROP VIEW IF EXISTS test2_view']])
1434+
->create();
1435+
1436+
$sql = $this->platform->getDropTablesSQL([$table1, $table2]);
1437+
1438+
// Verify extra drop SQL is present
1439+
self::assertContains('DROP VIEW IF EXISTS test1_view', $sql);
1440+
self::assertContains('DROP TRIGGER IF EXISTS test1_trigger', $sql);
1441+
self::assertContains('DROP VIEW IF EXISTS test2_view', $sql);
1442+
1443+
// Verify DROP TABLE statements are present
1444+
$dropTable1Sql = 'DROP TABLE ' . $table1->getQuotedName($this->platform);
1445+
$dropTable2Sql = 'DROP TABLE ' . $table2->getQuotedName($this->platform);
1446+
self::assertContains($dropTable1Sql, $sql);
1447+
self::assertContains($dropTable2Sql, $sql);
1448+
1449+
// Verify all expected SQL statements are present
1450+
// The implementation guarantees extra drop SQL comes before DROP TABLE statements
1451+
$hasDropTable1 = false;
1452+
$hasDropTable2 = false;
1453+
foreach ($sql as $statement) {
1454+
if ($statement === $dropTable1Sql) {
1455+
$hasDropTable1 = true;
1456+
}
1457+
1458+
if ($statement !== $dropTable2Sql) {
1459+
continue;
1460+
}
1461+
1462+
$hasDropTable2 = true;
1463+
}
1464+
1465+
self::assertTrue($hasDropTable1);
1466+
self::assertTrue($hasDropTable2);
1467+
}
1468+
1469+
public function testGetDropTablesSQLWithExtraDropSQLNonArrayThrowsException(): void
1470+
{
1471+
$table = Table::editor()
1472+
->setUnquotedName('test')
1473+
->setColumns(
1474+
Column::editor()
1475+
->setUnquotedName('id')
1476+
->setTypeName(Types::INTEGER)
1477+
->create(),
1478+
)
1479+
->setOptions([Table::OPTION_EXTRA_DROP_SQL => 'not an array'])
1480+
->create();
1481+
1482+
$this->expectException(InvalidArgumentException::class);
1483+
$this->expectExceptionMessage(sprintf('Table option "%s" must be an array', Table::OPTION_EXTRA_DROP_SQL));
1484+
1485+
$this->platform->getDropTablesSQL([$table]);
1486+
}
12821487
}

0 commit comments

Comments
 (0)