chore: complete update
This commit is contained in:
145
src/Framework/Database/Migration/MigrationRunner.php
Normal file
145
src/Framework/Database/Migration/MigrationRunner.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Database\Migration;
|
||||
|
||||
use App\Framework\Database\ConnectionInterface;
|
||||
use App\Framework\Database\Exception\DatabaseException;
|
||||
use App\Framework\Database\Transaction;
|
||||
|
||||
final class MigrationRunner
|
||||
{
|
||||
private ConnectionInterface $connection;
|
||||
private string $migrationsTable;
|
||||
|
||||
public function __construct(ConnectionInterface $connection, string $migrationsTable = 'migrations')
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->migrationsTable = $migrationsTable;
|
||||
$this->ensureMigrationsTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Migration[] $migrations
|
||||
*/
|
||||
public function migrate(array $migrations): array
|
||||
{
|
||||
$executedMigrations = [];
|
||||
$appliedVersions = $this->getAppliedVersions();
|
||||
|
||||
foreach ($migrations as $migration) {
|
||||
if (in_array($migration->getVersion(), $appliedVersions, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Transaction::run($this->connection, function() use ($migration) {
|
||||
echo "Migrating: {$migration->getVersion()} - {$migration->getDescription()}\n";
|
||||
|
||||
$migration->up($this->connection);
|
||||
|
||||
$this->connection->execute(
|
||||
"INSERT INTO {$this->migrationsTable} (version, description, executed_at) VALUES (?, ?, ?)",
|
||||
[$migration->getVersion(), $migration->getDescription(), date('Y-m-d H:i:s')]
|
||||
);
|
||||
});
|
||||
|
||||
$executedMigrations[] = $migration->getVersion();
|
||||
echo "Migrated: {$migration->getVersion()}\n";
|
||||
} catch (\Throwable $e) {
|
||||
throw new DatabaseException(
|
||||
"Migration {$migration->getVersion()} failed: {$e->getMessage()}",
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $executedMigrations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Migration[] $migrations
|
||||
*/
|
||||
public function rollback(array $migrations, int $steps = 1): array
|
||||
{
|
||||
$rolledBackMigrations = [];
|
||||
$appliedVersions = $this->getAppliedVersions();
|
||||
|
||||
$sortedMigrations = $migrations;
|
||||
usort($sortedMigrations, fn($a, $b) => $b->getVersion() <=> $a->getVersion());
|
||||
|
||||
$count = 0;
|
||||
foreach ($sortedMigrations as $migration) {
|
||||
if ($count >= $steps) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!in_array($migration->getVersion(), $appliedVersions, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Transaction::run($this->connection, function() use ($migration) {
|
||||
echo "Rolling back: {$migration->getVersion()} - {$migration->getDescription()}\n";
|
||||
|
||||
$migration->down($this->connection);
|
||||
|
||||
$this->connection->execute(
|
||||
"DELETE FROM {$this->migrationsTable} WHERE version = ?",
|
||||
[$migration->getVersion()]
|
||||
);
|
||||
});
|
||||
|
||||
$rolledBackMigrations[] = $migration->getVersion();
|
||||
$count++;
|
||||
echo "Rolled back: {$migration->getVersion()}\n";
|
||||
} catch (\Throwable $e) {
|
||||
throw new DatabaseException(
|
||||
"Rollback {$migration->getVersion()} failed: {$e->getMessage()}",
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $rolledBackMigrations;
|
||||
}
|
||||
|
||||
public function getStatus(array $migrations): array
|
||||
{
|
||||
$appliedVersions = $this->getAppliedVersions();
|
||||
$status = [];
|
||||
|
||||
foreach ($migrations as $migration) {
|
||||
$status[] = [
|
||||
'version' => $migration->getVersion(),
|
||||
'description' => $migration->getDescription(),
|
||||
'applied' => in_array($migration->getVersion(), $appliedVersions, true),
|
||||
];
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
private function getAppliedVersions(): array
|
||||
{
|
||||
return $this->connection->queryColumn(
|
||||
"SELECT version FROM {$this->migrationsTable} ORDER BY executed_at"
|
||||
);
|
||||
}
|
||||
|
||||
private function ensureMigrationsTable(): void
|
||||
{
|
||||
$sql = "CREATE TABLE IF NOT EXISTS {$this->migrationsTable} (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
version VARCHAR(255) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
executed_at DATETIME NOT NULL,
|
||||
INDEX idx_version (version)
|
||||
)";
|
||||
|
||||
$this->connection->execute($sql);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user