2121use DateTime ;
2222use Exception ;
2323use InvalidArgumentException ;
24+ use LogicException ;
2425use Migrations \Config \ConfigInterface ;
2526use Migrations \Migration \ManagerFactory ;
2627use Throwable ;
@@ -77,6 +78,9 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar
7778 ])->addOption ('date ' , [
7879 'short ' => 'd ' ,
7980 'help ' => 'The date to rollback to ' ,
81+ ])->addOption ('count ' , [
82+ 'short ' => 'k ' ,
83+ 'help ' => 'The number of migrations to rollback ' ,
8084 ])->addOption ('fake ' , [
8185 'help ' => "Mark any migrations selected as run, but don't actually execute them " ,
8286 'boolean ' => true ,
@@ -130,6 +134,17 @@ protected function executeMigrations(Arguments $args, ConsoleIo $io): ?int
130134 $ force = (bool )$ args ->getOption ('force ' );
131135 $ dryRun = (bool )$ args ->getOption ('dry-run ' );
132136
137+ $ count = $ args ->getOption ('count ' ) !== null ? (int )$ args ->getOption ('count ' ) : null ;
138+ if ($ count !== null && $ count < 1 ) {
139+ throw new LogicException ('Count must be > 0. ' );
140+ }
141+ if ($ count && $ date ) {
142+ throw new LogicException ('Can only use one of `--count` or `--date` options at a time. ' );
143+ }
144+ if ($ version && $ date ) {
145+ throw new LogicException ('Can only use one of `--version` or `--date` options at a time. ' );
146+ }
147+
133148 $ factory = new ManagerFactory ([
134149 'plugin ' => $ args ->getOption ('plugin ' ),
135150 'source ' => $ args ->getOption ('source ' ),
@@ -140,12 +155,12 @@ protected function executeMigrations(Arguments $args, ConsoleIo $io): ?int
140155 $ config = $ manager ->getConfig ();
141156
142157 $ versionOrder = $ config ->getVersionOrder ();
143- $ io ->out ('<info>using connection</info> ' . (string )$ args ->getOption ('connection ' ));
144- $ io ->out ('<info>using paths</info> ' . $ config ->getMigrationPath ());
145- $ io ->out ('<info>ordering by</info> ' . $ versionOrder . ' time ' );
158+ $ io ->verbose ('<info>using connection</info> ' . (string )$ args ->getOption ('connection ' ));
159+ $ io ->verbose ('<info>using paths</info> ' . $ config ->getMigrationPath ());
160+ $ io ->verbose ('<info>ordering by</info> ' . $ versionOrder . ' time ' );
146161
147162 if ($ dryRun ) {
148- $ io ->out ( ' <warning>dry-run mode enabled</warning> ' );
163+ $ io ->info ( ' DRY-RUN mode enabled ' );
149164 }
150165 if ($ fake ) {
151166 $ io ->out ('<warning>warning</warning> performing fake rollbacks ' );
@@ -162,30 +177,34 @@ protected function executeMigrations(Arguments $args, ConsoleIo $io): ?int
162177 try {
163178 // run the migrations
164179 $ start = microtime (true );
165- $ manager ->rollback ($ target , $ force , $ targetMustMatch , $ fake );
180+ if ($ count ) {
181+ $ manager ->rollbackByCount ($ count , $ force , $ fake );
182+ } else {
183+ $ manager ->rollback ($ target , $ force , $ targetMustMatch , $ fake );
184+ }
166185 $ end = microtime (true );
167186 } catch (Exception $ e ) {
168187 $ io ->err ('<error> ' . $ e ->getMessage () . '</error> ' );
169- $ io ->out ($ e ->getTraceAsString (), 1 , ConsoleIo:: VERBOSE );
188+ $ io ->verbose ($ e ->getTraceAsString ());
170189
171190 return self ::CODE_ERROR ;
172191 } catch (Throwable $ e ) {
173192 $ io ->err ('<error> ' . $ e ->getMessage () . '</error> ' );
174- $ io ->out ($ e ->getTraceAsString (), 1 , ConsoleIo:: VERBOSE );
193+ $ io ->verbose ($ e ->getTraceAsString ());
175194
176195 return self ::CODE_ERROR ;
177196 }
178197
198+ $ io ->comment ('All Done. Took ' . sprintf ('%.4fs ' , $ end - $ start ));
179199 $ io ->out ('' );
180- $ io ->out ('<comment>All Done. Took ' . sprintf ('%.4fs ' , $ end - $ start ) . '</comment> ' );
181200
182201 $ exitCode = self ::CODE_SUCCESS ;
183202
184203 // Run dump command to generate lock file
185204 if (!$ args ->getOption ('no-lock ' )) {
186- $ io ->out ('' );
187- $ io ->out ('Dumping the current schema of the database to be used while baking a diff ' );
188- $ io ->out ('' );
205+ $ io ->verbose ('' );
206+ $ io ->verbose ('Dumping the current schema of the database to be used while baking a diff ' );
207+ $ io ->verbose ('' );
189208
190209 $ newArgs = DumpCommand::extractArgs ($ args );
191210 $ exitCode = $ this ->executeCommand (DumpCommand::class, $ newArgs , $ io );
0 commit comments