PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => true, ]); } function dev_apply_schema(PDO $pdo): void { dev_apply_migrations($pdo); } function dev_migrations_dir(): string { return __DIR__ . '/../database/migrations'; } function dev_ensure_migration_table(PDO $pdo): void { $pdo->exec( 'CREATE TABLE IF NOT EXISTS schema_migrations ( version VARCHAR(255) PRIMARY KEY, applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' ); } /** * @return array */ function dev_applied_migrations(PDO $pdo): array { dev_ensure_migration_table($pdo); $applied = []; $stmt = $pdo->query('SELECT version FROM schema_migrations ORDER BY version'); foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $version) { $applied[(string)$version] = true; } return $applied; } /** * @return list Applied migration filenames. */ function dev_apply_migrations(PDO $pdo): array { $dir = dev_migrations_dir(); $files = glob($dir . '/*.sql'); if ($files === false || $files === []) { fwrite(STDERR, "No migration files found in {$dir}.\n"); exit(1); } sort($files, SORT_STRING); $applied = dev_applied_migrations($pdo); $newlyApplied = []; $insert = $pdo->prepare('INSERT INTO schema_migrations (version) VALUES (?)'); foreach ($files as $file) { $version = basename($file); if (isset($applied[$version])) { continue; } $sql = file_get_contents($file); if ($sql === false) { fwrite(STDERR, "Could not read migration file {$version}.\n"); exit(1); } try { $pdo->exec($sql); $insert->execute([$version]); $newlyApplied[] = $version; } catch (Throwable $e) { fwrite(STDERR, "Migration {$version} failed: {$e->getMessage()}\n"); exit(1); } } return $newlyApplied; }