-
Notifications
You must be signed in to change notification settings - Fork 0
/
MigrationRunner.php
150 lines (124 loc) · 4.44 KB
/
MigrationRunner.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
namespace Framework\Database\Migration;
use Framework\Config\Config;
use Framework\Database\Database;
use Framework\Facades\File;
use Framework\Facades\Path;
use RuntimeException;
class MigrationRunner
{
private string $migrationsPath = '';
public function __construct()
{
$this->migrationsPath = Path::join(__DIR__, '..', '..', '..', 'resources', 'Database', 'Migrations');
}
/** Apply all migrations */
public function run(): void
{
$this->runAllMigrations(Path::join(__DIR__, '..', '..', 'resources', 'Database', 'Migrations'));
$this->runAllMigrations($this->migrationsPath);
}
/** Run all the migration */
private function runAllMigrations(string $migrationsPath): void
{
$migrationFiles = $this->getMigrationFiles($migrationsPath);
sort($migrationFiles);
foreach ($migrationFiles as $migrationFile) {
$this->runMigration(Path::join($migrationsPath, $migrationFile));
}
}
/** Get all migration files from the migrations directory */
private function getMigrationFiles(string $migrationsPath): array
{
$allFiles = File::findFilesInDir($migrationsPath, onlyFiles: true);
$migrationFiles = [];
/** @var string $file */
foreach ($allFiles as $file) {
if (!$this->isMigrationFile($file)) {
continue;
}
array_push($migrationFiles, $file);
}
return $migrationFiles;
}
private function isMigrationFile(string $filename): bool
{
// Migration files cannot start with a dot
if (str_starts_with($filename, '.')) {
return false;
}
// All migration files must be PHP files
if (!str_ends_with($filename, '.php')) {
return false;
}
return true;
}
/** Run the given migration */
private function runMigration(string $filepath): void
{
if ($this->isMigrationAlreadyApplied($this->extractMigrationName($filepath))) {
return;
}
/** @var MigrationInterface $migration */
$migration = require $filepath;
$migration->run();
$this->addEntryToMigrationTable($filepath);
printLn('Applied ' . $this->extractMigrationName($filepath));
}
/** Checks if the given migration is already applied to the database */
private function isMigrationAlreadyApplied(string $migrationName): bool
{
if (!$this->doesMigrationsTableExists()) {
return false;
}
$result = Database::prepared(
'SELECT * FROM migrations WHERE `name` = ?',
's',
$migrationName
);
if ($result === false) {
return false;
}
return $result->numRows() === 1;
}
/** Extract the migration name out of the complete file path */
private function extractMigrationName(string $filepath): string
{
$path = explode(DIRECTORY_SEPARATOR, $filepath);
return str_replace('.php', '', $path[count($path) - 1]);
}
/** Insert the given migration file into the migration table */
private function addEntryToMigrationTable(string $migrationFile): void
{
Database::prepared(
'INSERT INTO migrations (`name`) VALUES (?)',
's',
$this->extractMigrationName($migrationFile)
);
}
/** Checks if the table `migrations` is already created */
private function doesMigrationsTableExists(): bool
{
// TODO Find a better solution for this
$result = false;
switch (Config::env('DB_CONNECTION')) {
case 'mariadb':
$result = Database::prepared(
'SELECT TABLE_NAME FROM information_schema.TABLES ' .
'WHERE TABLE_SCHEMA LIKE ? AND TABLE_TYPE LIKE \'BASE TABLE\' AND TABLE_NAME = \'migrations\'',
's',
Database::database()
);
break;
case 'sqlite':
$result = Database::unprepared('SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'migrations\'');
break;
default:
throw new RuntimeException('The database connection "' . Config::env('DB_CONNECTION') . '" is not supported');
}
if ($result === false) {
return false;
}
return $result->numRows() === 1;
}
}