AppMigration.php
2 years ago
AppMigrationTemplate.php
2 years ago
Cli.php
2 weeks ago
DbMigration.php
6 months ago
DbMigrationTemplate.php
2 years ago
Logger.php
2 years ago
Migrator.php
1 year ago
MigratorException.php
2 years ago
Repository.php
2 years ago
Runner.php
2 years ago
Store.php
6 months ago
index.php
3 years ago
Repository.php
107 lines
| 1 | <?php declare(strict_types = 1); |
| 2 | |
| 3 | namespace MailPoet\Migrator; |
| 4 | |
| 5 | if (!defined('ABSPATH')) exit; |
| 6 | |
| 7 | |
| 8 | use RecursiveDirectoryIterator; |
| 9 | use RecursiveIteratorIterator; |
| 10 | use SplFileInfo; |
| 11 | |
| 12 | class Repository { |
| 13 | const MIGRATIONS_LEVEL_APP = 'app'; |
| 14 | const MIGRATIONS_LEVEL_DB = 'db'; |
| 15 | |
| 16 | /** @var string */ |
| 17 | private $migrationsDir; |
| 18 | |
| 19 | /** @var string */ |
| 20 | private $templateFile; |
| 21 | |
| 22 | public function __construct() { |
| 23 | $this->migrationsDir = __DIR__ . '/../Migrations'; |
| 24 | $this->templateFile = __DIR__ . '/{level}MigrationTemplate.php'; |
| 25 | } |
| 26 | |
| 27 | public function getMigrationsDir(): string { |
| 28 | return $this->migrationsDir; |
| 29 | } |
| 30 | |
| 31 | /** @return array{name: string, path: string} */ |
| 32 | public function create(string $level): array { |
| 33 | if (!in_array($level, [self::MIGRATIONS_LEVEL_APP, self::MIGRATIONS_LEVEL_DB], true)) { |
| 34 | throw MigratorException::invalidMigrationLevel($level); |
| 35 | } |
| 36 | $ucFirstLevel = ucfirst($level); |
| 37 | $templateFile = str_replace('{level}', $ucFirstLevel, $this->templateFile); |
| 38 | $template = @file_get_contents($templateFile); |
| 39 | if (!$template) { |
| 40 | throw MigratorException::templateFileReadFailed($templateFile); |
| 41 | } |
| 42 | $name = $this->generateName($level); |
| 43 | $migration = str_replace('{level}', $ucFirstLevel, 'class {level}MigrationTemplate '); |
| 44 | $migration = str_replace($migration, "class $name ", $template); |
| 45 | $path = "$this->migrationsDir/$ucFirstLevel/$name.php"; |
| 46 | $result = @file_put_contents($path, $migration); |
| 47 | if (!$result) { |
| 48 | throw MigratorException::migrationFileWriteFailed($path); |
| 49 | } |
| 50 | return [ |
| 51 | 'name' => $name, |
| 52 | 'path' => $path, |
| 53 | ]; |
| 54 | } |
| 55 | |
| 56 | /** |
| 57 | * Array of migration filenames and types. |
| 58 | * Db migrations are loaded first, then app migrations. This ensures that Db migrator is run before app migrations |
| 59 | * @return array<array{level: string, name: string}> |
| 60 | */ |
| 61 | public function loadAll(): array { |
| 62 | $migrations = array_merge( |
| 63 | $this->loadForLevel(self::MIGRATIONS_LEVEL_DB), |
| 64 | $this->loadForLevel(self::MIGRATIONS_LEVEL_APP) |
| 65 | ); |
| 66 | $migrationNames = array_column($migrations, 'name'); |
| 67 | $duplicateNames = array_diff_assoc($migrationNames, array_unique($migrationNames)); |
| 68 | if (!empty($duplicateNames)) { |
| 69 | throw MigratorException::duplicateMigrationNames($duplicateNames); |
| 70 | } |
| 71 | return $migrations; |
| 72 | } |
| 73 | |
| 74 | /** |
| 75 | * @return array<array{level: string, name: string}> |
| 76 | */ |
| 77 | private function loadForLevel(string $level): array { |
| 78 | $files = new RecursiveIteratorIterator( |
| 79 | new RecursiveDirectoryIterator($this->migrationsDir . '/' . ucfirst($level), RecursiveDirectoryIterator::SKIP_DOTS) |
| 80 | ); |
| 81 | |
| 82 | $migrations = []; |
| 83 | foreach ($files as $file) { |
| 84 | if (!$file instanceof SplFileInfo || !$file->isFile()) { |
| 85 | continue; |
| 86 | } |
| 87 | if (strtolower($file->getFilename()) === 'index.php') { |
| 88 | continue; |
| 89 | } |
| 90 | if (strtolower($file->getExtension()) === 'php') { |
| 91 | $migrations[] = $file->getBasename('.' . $file->getExtension()); |
| 92 | } |
| 93 | } |
| 94 | sort($migrations); |
| 95 | return array_map(function ($migration) use ($level) { |
| 96 | return [ |
| 97 | 'level' => $level, |
| 98 | 'name' => $migration, |
| 99 | ]; |
| 100 | }, $migrations); |
| 101 | } |
| 102 | |
| 103 | private function generateName(string $level): string { |
| 104 | return 'Migration_' . gmdate('Ymd_His') . '_' . ucfirst($level); |
| 105 | } |
| 106 | } |
| 107 |