65 lines
1.5 KiB
PHP
65 lines
1.5 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Applies any pending SQL migrations from migrations/*.sql, in filename order.
|
||
|
|
* Each applied file is recorded in the schema_migrations table so re-running is
|
||
|
|
* safe. Usage: php bin/migrate.php (or: composer migrate)
|
||
|
|
*/
|
||
|
|
|
||
|
|
use App\Support\Config;
|
||
|
|
use App\Support\Database;
|
||
|
|
|
||
|
|
require __DIR__ . '/../vendor/autoload.php';
|
||
|
|
|
||
|
|
$config = Config::load(dirname(__DIR__));
|
||
|
|
$pdo = (new Database($config->databasePath))->pdo();
|
||
|
|
|
||
|
|
$pdo->exec(
|
||
|
|
'CREATE TABLE IF NOT EXISTS schema_migrations (
|
||
|
|
filename TEXT PRIMARY KEY,
|
||
|
|
applied_at TEXT NOT NULL DEFAULT (strftime(\'%Y-%m-%dT%H:%M:%SZ\', \'now\'))
|
||
|
|
)'
|
||
|
|
);
|
||
|
|
|
||
|
|
$applied = $pdo->query('SELECT filename FROM schema_migrations')
|
||
|
|
->fetchAll(PDO::FETCH_COLUMN);
|
||
|
|
|
||
|
|
$files = glob(dirname(__DIR__) . '/migrations/*.sql') ?: [];
|
||
|
|
sort($files);
|
||
|
|
|
||
|
|
$count = 0;
|
||
|
|
|
||
|
|
foreach ($files as $file) {
|
||
|
|
$name = basename($file);
|
||
|
|
|
||
|
|
if (in_array($name, $applied, true)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$sql = (string) file_get_contents($file);
|
||
|
|
|
||
|
|
$pdo->beginTransaction();
|
||
|
|
|
||
|
|
try {
|
||
|
|
$pdo->exec($sql);
|
||
|
|
|
||
|
|
$record = $pdo->prepare('INSERT INTO schema_migrations (filename) VALUES (?)');
|
||
|
|
$record->execute([$name]);
|
||
|
|
|
||
|
|
$pdo->commit();
|
||
|
|
} catch (Throwable $e) {
|
||
|
|
$pdo->rollBack();
|
||
|
|
fwrite(STDERR, "Failed to apply {$name}: {$e->getMessage()}\n");
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
echo "Applied {$name}\n";
|
||
|
|
$count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
echo $count === 0
|
||
|
|
? "Database is up to date; nothing to apply.\n"
|
||
|
|
: "Done. Applied {$count} migration(s).\n";
|