Skip to content

Commit 4461726

Browse files
committed
fix: correct migrateTo logic to use migration order instead of apply_time
- Fix migrateTo to find currentIndex based on migration order, not apply_time - This ensures rollback works correctly when migrations are applied in order - Fixes issue where migrateTo was not correctly rolling back migrations - All 2204 tests passing
1 parent f490e54 commit 4461726

File tree

1 file changed

+35
-42
lines changed

1 file changed

+35
-42
lines changed

src/migrations/MigrationRunner.php

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -259,59 +259,52 @@ protected function migrateDownByVersion(string $version): void
259259
*/
260260
public function migrateTo(string $version): void
261261
{
262+
$allMigrations = $this->getAllMigrationFiles();
263+
$targetIndex = array_search($version, $allMigrations, true);
264+
265+
if ($targetIndex === false) {
266+
throw new QueryException("Migration version {$version} not found");
267+
}
268+
262269
$history = $this->getMigrationHistory();
263-
$currentVersion = $this->getMigrationVersion();
264-
265-
if ($currentVersion === null) {
266-
// Apply all migrations up to version
267-
$allMigrations = $this->getAllMigrationFiles();
268-
$targetIndex = array_search($version, $allMigrations, true);
269-
if ($targetIndex === false) {
270-
throw new QueryException("Migration version {$version} not found");
270+
$appliedVersions = array_column($history, 'version');
271+
272+
// Find the highest applied migration version (by order in allMigrations, not by apply_time)
273+
$currentIndex = -1;
274+
foreach ($appliedVersions as $appliedVersion) {
275+
$index = array_search($appliedVersion, $allMigrations, true);
276+
if ($index !== false && $index > $currentIndex) {
277+
$currentIndex = $index;
271278
}
279+
}
272280

281+
if ($currentIndex === -1) {
282+
// No migrations applied, apply all up to target version
273283
$migrationsToApply = array_slice($allMigrations, 0, $targetIndex + 1);
274284
foreach ($migrationsToApply as $migrationVersion) {
275285
$this->migrateUp($migrationVersion);
276286
}
277-
} elseif ($currentVersion === $version) {
287+
} elseif ($currentIndex === $targetIndex) {
278288
// Already at target version
279289
return;
280-
} else {
281-
// Rollback or apply migrations
282-
$allMigrations = $this->getAllMigrationFiles();
283-
$currentIndex = array_search($currentVersion, $allMigrations, true);
284-
$targetIndex = array_search($version, $allMigrations, true);
285-
286-
if ($targetIndex === false) {
287-
throw new QueryException("Migration version {$version} not found");
288-
}
289-
290-
if ($targetIndex < $currentIndex) {
291-
// Rollback migrations in reverse order (newest first)
292-
// We need to rollback from currentIndex down to targetIndex+1
293-
$migrationsToRollback = array_slice($allMigrations, $targetIndex + 1, $currentIndex - $targetIndex);
294-
295-
// Get current history once before rollback loop
296-
$history = $this->getMigrationHistory();
297-
$appliedVersions = array_column($history, 'version');
298-
299-
// Rollback each migration that needs to be rolled back, in reverse order
300-
foreach (array_reverse($migrationsToRollback) as $migrationVersion) {
301-
// Only rollback if migration is actually applied
302-
if (in_array($migrationVersion, $appliedVersions, true)) {
303-
$this->migrateDownByVersion($migrationVersion);
304-
// Remove from appliedVersions to avoid duplicate rollback attempts
305-
$appliedVersions = array_values(array_diff($appliedVersions, [$migrationVersion]));
306-
}
307-
}
308-
} else {
309-
// Apply
310-
$migrationsToApply = array_slice($allMigrations, $currentIndex + 1, $targetIndex - $currentIndex);
311-
foreach ($migrationsToApply as $migrationVersion) {
312-
$this->migrateUp($migrationVersion);
290+
} elseif ($targetIndex < $currentIndex) {
291+
// Rollback migrations in reverse order (newest first)
292+
// We need to rollback from currentIndex down to targetIndex+1
293+
$migrationsToRollback = array_slice($allMigrations, $targetIndex + 1, $currentIndex - $targetIndex);
294+
295+
// Rollback each migration that needs to be rolled back, in reverse order
296+
foreach (array_reverse($migrationsToRollback) as $migrationVersion) {
297+
// Only rollback if migration is actually applied
298+
if (in_array($migrationVersion, $appliedVersions, true)) {
299+
$this->migrateDownByVersion($migrationVersion);
313300
}
314301
}
302+
} else {
303+
// Apply
304+
$migrationsToApply = array_slice($allMigrations, $currentIndex + 1, $targetIndex - $currentIndex);
305+
foreach ($migrationsToApply as $migrationVersion) {
306+
$this->migrateUp($migrationVersion);
307+
}
315308
}
316309
}
317310

0 commit comments

Comments
 (0)