Automatische DB-Migrationen beim Container-Start

This commit is contained in:
fds2610 2026-03-29 13:19:15 +02:00
parent c9f5dd02f8
commit 44917852c6
2 changed files with 103 additions and 0 deletions

View file

@ -1,4 +1,8 @@
#!/bin/sh #!/bin/sh
# Fix ownership of volume-mounted upload directory at container start # Fix ownership of volume-mounted upload directory at container start
chown -R www-data:www-data /var/www/html/public/static/uploads 2>/dev/null || true chown -R www-data:www-data /var/www/html/public/static/uploads 2>/dev/null || true
# Datenbank-Migrationen automatisch einspielen
php /var/www/html/scripts/migrate.php
exec "$@" exec "$@"

99
scripts/migrate.php Normal file
View file

@ -0,0 +1,99 @@
<?php
/**
* Automatisches Migrations-Script
* Wird beim Start des web-Containers ausgeführt (nach DB-Healthcheck).
* Prüft welche migrations/*.sql noch nicht angewendet wurden und führt sie aus.
*/
$host = getenv('DB_HOST') ?: 'db';
$dbName = getenv('DB_NAME') ?: 'steuerkram';
$dbUser = getenv('DB_USER') ?: 'steuerkram';
$dbPass = getenv('DB_PASS') ?: 'steuerkram';
$migrDir = __DIR__ . '/../migrations';
function mlog(string $msg): void {
echo '[migrate] ' . $msg . PHP_EOL;
}
mlog('Starte Migrations-Prüfung...');
try {
$pdo = new PDO(
"mysql:host=$host;dbname=$dbName;charset=utf8mb4",
$dbUser,
$dbPass,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
} catch (PDOException $e) {
echo '[migrate] FEHLER: DB-Verbindung fehlgeschlagen: ' . $e->getMessage() . PHP_EOL;
exit(1);
}
// schema_migrations anlegen falls nicht vorhanden
$pdo->exec('CREATE TABLE IF NOT EXISTS schema_migrations (
migration VARCHAR(255) NOT NULL PRIMARY KEY,
applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
)');
// Alle vorhandenen Migrations-Dateien ermitteln (alphabetisch)
$files = glob($migrDir . '/*.sql');
sort($files);
if (empty($files)) {
mlog('Keine Migrations-Dateien gefunden.');
exit(0);
}
// Prüfen ob schema_migrations leer ist, aber belege bereits existiert
// → bestehender Server: alle Dateien als applied markieren ohne Ausführung
$migrationCount = (int)$pdo->query('SELECT COUNT(*) FROM schema_migrations')->fetchColumn();
$belegeExists = (int)$pdo->query(
"SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'belege'"
)->fetchColumn();
if ($migrationCount === 0 && $belegeExists === 1) {
mlog('Bestehende Datenbank erkannt – markiere vorhandene Migrations-Dateien als applied...');
$stmt = $pdo->prepare('INSERT IGNORE INTO schema_migrations (migration) VALUES (?)');
foreach ($files as $file) {
$name = basename($file);
$stmt->execute([$name]);
mlog(' markiert: ' . $name);
}
mlog('Fertig – keine Migrationen ausgeführt.');
exit(0);
}
// Bereits angewendete Migrationen laden
$applied = $pdo->query('SELECT migration FROM schema_migrations')
->fetchAll(PDO::FETCH_COLUMN);
$applied = array_flip($applied);
// Neue Migrationen ausführen
$count = 0;
foreach ($files as $file) {
$name = basename($file);
if (isset($applied[$name])) {
continue;
}
mlog('Führe aus: ' . $name);
$sql = file_get_contents($file);
try {
// Mehrteilige SQL-Dateien (mehrere Statements) aufteilen und einzeln ausführen
$pdo->exec($sql);
$pdo->prepare('INSERT INTO schema_migrations (migration) VALUES (?)')
->execute([$name]);
$count++;
} catch (PDOException $e) {
echo '[migrate] FEHLER bei ' . $name . ': ' . $e->getMessage() . PHP_EOL;
exit(1);
}
}
if ($count === 0) {
mlog('Datenbank ist aktuell – keine Migrationen notwendig.');
} else {
mlog($count . ' Migration(en) erfolgreich angewendet.');
}