Skip to content

Commit 4ce7f28

Browse files
author
Vítězslav Dvořák
committed
Adds translation tables and updates column types
Implements the creation of translation tables for applications and configurations, ensuring proper foreign key relationships. Refines previously defined migration processes to account for column type correctness, supporting better data integrity across tables. Includes enhancements to handle reserved word columns, improving overall database compatibility. Improves migration scripts for future translations functionality.
1 parent 8440b48 commit 4ce7f28

File tree

4 files changed

+118
-74
lines changed

4 files changed

+118
-74
lines changed

db/migrations/20251008184819_add_translations.php

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,48 @@
22

33
declare(strict_types=1);
44

5+
/**
6+
* This file is part of the MultiFlexi package
7+
*
8+
* https://multiflexi.eu/
9+
*
10+
* (c) Vítězslav Dvořák <http://vitexsoftware.com>
11+
*
12+
* For the full copyright and license information, please view the LICENSE
13+
* file that was distributed with this source code.
14+
*/
15+
516
use Phinx\Migration\AbstractMigration;
617

718
final class AddTranslations extends AbstractMigration
819
{
920
public function change(): void
1021
{
1122
// === CREATE TRANSLATION TABLES ===
12-
1323
// apps translations
1424
$databaseType = $this->getAdapter()->getOption('adapter');
1525
$unsigned = ($databaseType === 'mysql') ? ['signed' => false] : [];
1626

17-
if (!$this->hasTable('app_translations')) {
18-
$appTranslations = $this->table('app_translations');
19-
$appTranslations
20-
->addColumn('app_id', 'integer', ['null' => false, 'signed' => true])
21-
->addColumn('lang', 'string', ['limit' => 5, 'null' => false])
22-
->addColumn('name', 'string', ['limit' => 255, 'null' => true, 'default' => null])
23-
->addColumn('title', 'string', ['limit' => 255, 'null' => true, 'default' => null])
24-
->addColumn('description', 'text', ['null' => true, 'default' => null])
25-
->addIndex(['app_id', 'lang'], ['unique' => true, 'name' => 'idx_app_lang'])
26-
->addForeignKey('app_id', 'apps', 'id', ['delete'=> 'CASCADE', 'update'=> 'NO_ACTION'])
27-
->create();
28-
}
27+
$appTranslations = $this->table('app_translations');
28+
$appTranslations
29+
->addColumn('app_id', 'integer', array_merge(['null' => false], $unsigned))
30+
->addColumn('lang', 'string', ['limit' => 5, 'null' => false])
31+
->addColumn('name', 'string', ['limit' => 255, 'null' => true, 'default' => null])
32+
->addColumn('title', 'string', ['limit' => 255, 'null' => true, 'default' => null])
33+
->addColumn('description', 'text', ['null' => true, 'default' => null])
34+
->addIndex(['app_id', 'lang'], ['unique' => true, 'name' => 'idx_app_lang'])
35+
->addForeignKey('app_id', 'apps', 'id', ['delete' => 'CASCADE', 'update' => 'NO_ACTION'])
36+
->create();
2937

30-
// configuration translations
31-
if (!$this->hasTable('configuration_translations')) {
32-
$cfgTranslations = $this->table('configuration_translations');
33-
$cfgTranslations
34-
->addColumn('configuration_id', 'integer', ['null' => false, 'signed' => true])
35-
->addColumn('lang', 'string', ['limit' => 5, 'null' => false])
36-
->addColumn('name', 'string', ['limit' => 255, 'null' => true, 'default' => null])
37-
->addColumn('description', 'text', ['null' => true, 'default' => null])
38-
->addColumn('hint', 'text', ['null' => true, 'default' => null])
39-
->addIndex(['configuration_id','lang'], ['unique' => true, 'name' => 'idx_conf_lang'])
40-
->addForeignKey('configuration_id', 'configuration', 'id', ['delete'=> 'CASCADE', 'update'=> 'NO_ACTION'])
41-
->create();
42-
}
38+
$cfgTranslations = $this->table('configuration_translations');
39+
$cfgTranslations
40+
->addColumn('configuration_id', 'integer', array_merge(['null' => false], $unsigned))
41+
->addColumn('lang', 'string', ['limit' => 5, 'null' => false])
42+
->addColumn('name', 'string', ['limit' => 255, 'null' => true, 'default' => null])
43+
->addColumn('description', 'text', ['null' => true, 'default' => null])
44+
->addColumn('hint', 'text', ['null' => true, 'default' => null])
45+
->addIndex(['configuration_id', 'lang'], ['unique' => true, 'name' => 'idx_conf_lang'])
46+
->addForeignKey('configuration_id', 'configuration', 'id', ['delete' => 'CASCADE', 'update' => 'NO_ACTION'])
47+
->create();
4348
}
44-
4549
}

db/migrations/20251010131956_ensure_apps_and_configuration_tables.php

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
declare(strict_types=1);
44

5+
/**
6+
* This file is part of the MultiFlexi package
7+
*
8+
* https://multiflexi.eu/
9+
*
10+
* (c) Vítězslav Dvořák <http://vitexsoftware.com>
11+
*
12+
* For the full copyright and license information, please view the LICENSE
13+
* file that was distributed with this source code.
14+
*/
15+
516
use Phinx\Migration\AbstractMigration;
617

718
final class EnsureAppsAndConfigurationTables extends AbstractMigration
@@ -17,19 +28,20 @@ public function up(): void
1728
$table = $this->table('configuration');
1829
$columns = $this->getAdapter()->getColumns('configuration');
1930
$hasIdColumn = false;
20-
31+
2132
foreach ($columns as $column) {
2233
if ($column->getName() === 'id') {
2334
$hasIdColumn = true;
35+
2436
break;
2537
}
2638
}
27-
39+
2840
if (!$hasIdColumn) {
2941
// The table exists without id, we need to add it
3042
// This is complex because the table was created without specifying id: false
3143
// Phinx by default adds an id column, so this table must have been created differently
32-
44+
3345
// Create a temporary table with the structure we want
3446
$tempTable = $this->table('configuration_temp');
3547
$tempTable
@@ -46,7 +58,7 @@ public function up(): void
4658
->create();
4759

4860
// Copy data
49-
$this->execute('INSERT INTO configuration_temp (app_id, company_id, runtemplate_id, `key`, name, value) ' .
61+
$this->execute('INSERT INTO configuration_temp (app_id, company_id, runtemplate_id, `key`, name, value) '.
5062
'SELECT app_id, company_id, runtemplate_id, `key`, `key` as name, value FROM configuration');
5163

5264
// Drop old table
@@ -62,14 +74,15 @@ public function up(): void
6274
$table = $this->table('conffield');
6375
$columns = $this->getAdapter()->getColumns('conffield');
6476
$hasIdColumn = false;
65-
77+
6678
foreach ($columns as $column) {
6779
if ($column->getName() === 'id') {
6880
$hasIdColumn = true;
81+
6982
break;
7083
}
7184
}
72-
85+
7386
if (!$hasIdColumn) {
7487
// Create temporary table with id
7588
$tempTable = $this->table('conffield_temp');
@@ -84,15 +97,15 @@ public function up(): void
8497
->create();
8598

8699
// Copy data
87-
$this->execute('INSERT INTO conffield_temp (app_id, keyname, type, description) ' .
100+
$this->execute('INSERT INTO conffield_temp (app_id, keyname, type, description) '.
88101
'SELECT app_id, keyname, type, description FROM conffield');
89102

90103
// Drop old table
91104
$this->table('conffield')->drop()->save();
92105

93106
// Rename temp table
94107
$this->execute('ALTER TABLE conffield_temp RENAME TO conffield');
95-
108+
96109
// Re-add indexes and foreign keys
97110
$this->table('conffield')
98111
->addIndex(['app_id', 'keyname'], ['unique' => true])

db/migrations/20251010132645_fix_configuration_id_type.php

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,85 @@
22

33
declare(strict_types=1);
44

5+
/**
6+
* This file is part of the MultiFlexi package
7+
*
8+
* https://multiflexi.eu/
9+
*
10+
* (c) Vítězslav Dvořák <http://vitexsoftware.com>
11+
*
12+
* For the full copyright and license information, please view the LICENSE
13+
* file that was distributed with this source code.
14+
*/
15+
516
use Phinx\Migration\AbstractMigration;
617

718
final class FixConfigurationIdType extends AbstractMigration
819
{
920
/**
10-
* This migration detects the actual column types and prepares for translations
21+
* This migration detects the actual column types and prepares for translations.
1122
*/
1223
public function up(): void
1324
{
1425
// Check if we're on MySQL/MariaDB
1526
$databaseType = $this->getAdapter()->getOption('adapter');
16-
27+
1728
if ($databaseType === 'mysql') {
1829
// Get the actual column info for configuration.id
19-
$sql = "SELECT COLUMN_TYPE, IS_NULLABLE, EXTRA FROM INFORMATION_SCHEMA.COLUMNS " .
30+
$sql = 'SELECT COLUMN_TYPE, IS_NULLABLE, EXTRA FROM INFORMATION_SCHEMA.COLUMNS '.
2031
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'configuration' AND COLUMN_NAME = 'id'";
2132
$configIdInfo = $this->fetchRow($sql);
22-
33+
2334
// Get the actual column info for apps.id
24-
$sql = "SELECT COLUMN_TYPE, IS_NULLABLE, EXTRA FROM INFORMATION_SCHEMA.COLUMNS " .
35+
$sql = 'SELECT COLUMN_TYPE, IS_NULLABLE, EXTRA FROM INFORMATION_SCHEMA.COLUMNS '.
2536
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apps' AND COLUMN_NAME = 'id'";
2637
$appsIdInfo = $this->fetchRow($sql);
27-
38+
2839
// Store the column types in a temporary table for the next migration
29-
$this->execute("CREATE TEMPORARY TABLE IF NOT EXISTS _migration_column_types (" .
30-
"table_name VARCHAR(64), " .
31-
"column_name VARCHAR(64), " .
32-
"column_type VARCHAR(64), " .
33-
"is_unsigned BOOLEAN" .
34-
")");
35-
40+
$this->execute('CREATE TEMPORARY TABLE IF NOT EXISTS _migration_column_types ('.
41+
'table_name VARCHAR(64), '.
42+
'column_name VARCHAR(64), '.
43+
'column_type VARCHAR(64), '.
44+
'is_unsigned BOOLEAN'.
45+
')');
46+
3647
// Check if configuration.id is unsigned
37-
$configIsUnsigned = strpos($configIdInfo['COLUMN_TYPE'], 'unsigned') !== false;
38-
$appsIsUnsigned = strpos($appsIdInfo['COLUMN_TYPE'], 'unsigned') !== false;
39-
40-
echo "Configuration ID type: " . $configIdInfo['COLUMN_TYPE'] . " (unsigned: " . ($configIsUnsigned ? 'yes' : 'no') . ")\n";
41-
echo "Apps ID type: " . $appsIdInfo['COLUMN_TYPE'] . " (unsigned: " . ($appsIsUnsigned ? 'yes' : 'no') . ")\n";
42-
48+
$configIsUnsigned = str_contains($configIdInfo['COLUMN_TYPE'], 'unsigned');
49+
$appsIsUnsigned = str_contains($appsIdInfo['COLUMN_TYPE'], 'unsigned');
50+
51+
echo 'Configuration ID type: '.$configIdInfo['COLUMN_TYPE'].' (unsigned: '.($configIsUnsigned ? 'yes' : 'no').")\n";
52+
echo 'Apps ID type: '.$appsIdInfo['COLUMN_TYPE'].' (unsigned: '.($appsIsUnsigned ? 'yes' : 'no').")\n";
53+
4354
// Fix the AddTranslations migration to use correct types
4455
// We'll update the migration file directly
45-
$migrationFile = __DIR__ . '/20251008184819_add_translations.php';
56+
$migrationFile = __DIR__.'/20251008184819_add_translations.php';
57+
4658
if (file_exists($migrationFile)) {
4759
$content = file_get_contents($migrationFile);
48-
60+
4961
// If configuration.id is signed, we need to use signed integers for the foreign key
5062
if (!$configIsUnsigned) {
5163
$newContent = str_replace(
5264
"->addColumn('configuration_id', 'integer', array_merge(['null' => false], \$unsigned))",
5365
"->addColumn('configuration_id', 'integer', ['null' => false, 'signed' => true])",
54-
$content
66+
$content,
5567
);
68+
5669
if ($newContent !== $content) {
5770
file_put_contents($migrationFile, $newContent);
5871
echo "Updated AddTranslations migration to use signed integer for configuration_id\n";
5972
}
6073
}
61-
74+
6275
// If apps.id is signed, we need to use signed integers for the foreign key
6376
if (!$appsIsUnsigned) {
6477
$content = file_get_contents($migrationFile);
6578
$newContent = str_replace(
6679
"->addColumn('app_id', 'integer', array_merge(['null' => false], \$unsigned))",
6780
"->addColumn('app_id', 'integer', ['null' => false, 'signed' => true])",
68-
$content
81+
$content,
6982
);
83+
7084
if ($newContent !== $content) {
7185
file_put_contents($migrationFile, $newContent);
7286
echo "Updated AddTranslations migration to use signed integer for app_id\n";
@@ -75,7 +89,7 @@ public function up(): void
7589
}
7690
}
7791
}
78-
92+
7993
public function down(): void
8094
{
8195
// Not reversible

db/migrations/20251010134500_rename_reserved_word_columns.php

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
declare(strict_types=1);
44

5+
/**
6+
* This file is part of the MultiFlexi package
7+
*
8+
* https://multiflexi.eu/
9+
*
10+
* (c) Vítězslav Dvořák <http://vitexsoftware.com>
11+
*
12+
* For the full copyright and license information, please view the LICENSE
13+
* file that was distributed with this source code.
14+
*/
15+
516
use Phinx\Migration\AbstractMigration;
617

718
final class RenameReservedWordColumns extends AbstractMigration
@@ -16,44 +27,46 @@ public function change(): void
1627
// 'key' is a reserved word in MySQL and PostgreSQL
1728
if ($this->hasTable('configuration')) {
1829
$table = $this->table('configuration');
19-
30+
2031
// Check if the column exists before renaming
2132
if ($table->hasColumn('key')) {
2233
$table->renameColumn('key', 'config_key')
23-
->update();
34+
->update();
2435
}
2536
}
26-
37+
2738
// Rename 'type' column in credential_type table to 'cred_type' if it exists
2839
// 'type' is a reserved word in PostgreSQL
2940
if ($this->hasTable('credential_type')) {
3041
$table = $this->table('credential_type');
31-
42+
3243
if ($table->hasColumn('type')) {
3344
$table->renameColumn('type', 'cred_type')
34-
->update();
45+
->update();
3546
}
3647
}
37-
48+
3849
// Update any other tables that might have reserved word columns
3950
// Common reserved words across databases: key, type, user, group, order, desc, asc, table, column, index
40-
51+
4152
// For the 'type' column in configuration table, rename to 'config_type'
4253
if ($this->hasTable('configuration')) {
4354
$table = $this->table('configuration');
44-
55+
4556
if ($table->hasColumn('type')) {
4657
$table->renameColumn('type', 'config_type')
47-
->update();
58+
->update();
4859
}
4960
}
50-
61+
5162
// For any 'user' columns (reserved in PostgreSQL), rename to appropriate names
5263
// Example: if there's a 'user' column in any table, rename it to 'user_id' or 'username'
53-
54-
$this->execute("
64+
65+
$this->execute(<<<'EOD'
66+
5567
-- Update any stored procedures, triggers, or views that reference these columns
5668
-- This is database-specific and might need manual intervention
57-
");
69+
70+
EOD);
5871
}
59-
}
72+
}

0 commit comments

Comments
 (0)