151 lines
4.7 KiB
PHP
151 lines
4.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require __DIR__ . '/dev-db.php';
|
|
|
|
if (PHP_SAPI !== 'cli') {
|
|
http_response_code(404);
|
|
exit;
|
|
}
|
|
|
|
$options = getopt('', ['source-prefix:', 'target-prefix:', 'replace']);
|
|
$sourcePrefix = app_validate_db_table_prefix((string)($options['source-prefix'] ?? ''));
|
|
$targetOption = $options['target-prefix'] ?? null;
|
|
if (!is_string($targetOption) || trim($targetOption) === '') {
|
|
fwrite(STDERR, "Aufruf: php scripts/migrate-table-prefix.php --target-prefix=test_ --replace [--source-prefix=alt_]\n");
|
|
exit(1);
|
|
}
|
|
$targetPrefix = app_validate_db_table_prefix($targetOption);
|
|
|
|
if ($sourcePrefix === $targetPrefix) {
|
|
fwrite(STDERR, "Quell- und Ziel-Prefix müssen verschieden sein.\n");
|
|
exit(1);
|
|
}
|
|
if (!array_key_exists('replace', $options)) {
|
|
fwrite(STDERR, "Abbruch: --replace ist erforderlich, weil vorhandene Ziel-Testdaten ersetzt werden.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/** @return string */
|
|
$quoteIdentifier = static function (string $name): string {
|
|
return '`' . str_replace('`', '``', $name) . '`';
|
|
};
|
|
|
|
$rawPdo = dev_pdo_for_prefix('');
|
|
$targetPdo = dev_pdo_for_prefix($targetPrefix);
|
|
|
|
echo "Zielschema {$targetPrefix} wird auf den aktuellen Migrationsstand gebracht.\n";
|
|
$applied = dev_apply_migrations($targetPdo);
|
|
echo count($applied) . " neue Migration(en) für {$targetPrefix} angewendet.\n";
|
|
|
|
$tableExists = static function (PDO $pdo, string $table): bool {
|
|
$stmt = $pdo->prepare(
|
|
'SELECT 1 FROM INFORMATION_SCHEMA.TABLES
|
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?'
|
|
);
|
|
$stmt->execute([$table]);
|
|
|
|
return $stmt->fetchColumn() !== false;
|
|
};
|
|
|
|
/** @return list<string> */
|
|
$tableColumns = static function (PDO $pdo, string $table): array {
|
|
$stmt = $pdo->prepare(
|
|
'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
|
|
ORDER BY ORDINAL_POSITION'
|
|
);
|
|
$stmt->execute([$table]);
|
|
|
|
return array_map('strval', $stmt->fetchAll(PDO::FETCH_COLUMN));
|
|
};
|
|
|
|
$targetsToClear = [];
|
|
$copies = [];
|
|
$sourceTableCount = 0;
|
|
|
|
foreach (app_database_table_names() as $baseName) {
|
|
if ($baseName === 'schema_migrations') {
|
|
continue;
|
|
}
|
|
|
|
$sourceTable = app_db_table_name($baseName, $sourcePrefix);
|
|
$targetTable = app_db_table_name($baseName, $targetPrefix);
|
|
$sourceExists = $tableExists($rawPdo, $sourceTable);
|
|
$targetExists = $tableExists($rawPdo, $targetTable);
|
|
|
|
if ($sourceExists) {
|
|
$sourceTableCount++;
|
|
}
|
|
if ($sourceExists && !$targetExists) {
|
|
throw new RuntimeException("Zieltabelle {$targetTable} fehlt nach den Migrationen.");
|
|
}
|
|
if (!$targetExists) {
|
|
continue;
|
|
}
|
|
|
|
$targetsToClear[] = $targetTable;
|
|
if (!$sourceExists) {
|
|
continue;
|
|
}
|
|
|
|
$sourceColumns = $tableColumns($rawPdo, $sourceTable);
|
|
$targetColumns = $tableColumns($rawPdo, $targetTable);
|
|
if ($sourceColumns !== $targetColumns) {
|
|
throw new RuntimeException("Spalten von {$sourceTable} und {$targetTable} stimmen nicht überein.");
|
|
}
|
|
$copies[] = [$sourceTable, $targetTable, $sourceColumns];
|
|
}
|
|
|
|
if ($sourceTableCount === 0) {
|
|
throw new RuntimeException('Im Quellschema wurden keine Anwendungstabellen gefunden.');
|
|
}
|
|
|
|
$copiedRows = 0;
|
|
$rawPdo->exec('SET FOREIGN_KEY_CHECKS = 0');
|
|
try {
|
|
$rawPdo->beginTransaction();
|
|
|
|
foreach ($targetsToClear as $targetTable) {
|
|
$rawPdo->exec('DELETE FROM ' . $quoteIdentifier($targetTable));
|
|
}
|
|
|
|
foreach ($copies as [$sourceTable, $targetTable, $columns]) {
|
|
$quotedColumns = implode(', ', array_map($quoteIdentifier, $columns));
|
|
$sourceRows = (int)$rawPdo
|
|
->query('SELECT COUNT(*) FROM ' . $quoteIdentifier($sourceTable))
|
|
->fetchColumn();
|
|
|
|
if ($sourceRows > 0) {
|
|
$rawPdo->exec(
|
|
'INSERT INTO ' . $quoteIdentifier($targetTable)
|
|
. ' (' . $quotedColumns . ') SELECT ' . $quotedColumns
|
|
. ' FROM ' . $quoteIdentifier($sourceTable)
|
|
);
|
|
}
|
|
|
|
$targetRows = (int)$rawPdo
|
|
->query('SELECT COUNT(*) FROM ' . $quoteIdentifier($targetTable))
|
|
->fetchColumn();
|
|
if ($sourceRows !== $targetRows) {
|
|
throw new RuntimeException(
|
|
"Zeilenzahl stimmt für {$sourceTable} -> {$targetTable} nicht: {$sourceRows} != {$targetRows}."
|
|
);
|
|
}
|
|
$copiedRows += $targetRows;
|
|
echo "{$sourceTable} -> {$targetTable}: {$targetRows} Zeile(n)\n";
|
|
}
|
|
|
|
$rawPdo->commit();
|
|
} catch (Throwable $e) {
|
|
if ($rawPdo->inTransaction()) {
|
|
$rawPdo->rollBack();
|
|
}
|
|
throw $e;
|
|
} finally {
|
|
$rawPdo->exec('SET FOREIGN_KEY_CHECKS = 1');
|
|
}
|
|
|
|
echo "Datenübernahme abgeschlossen: {$copiedRows} Zeile(n). Das Quellschema blieb unverändert.\n";
|