@@ -56,6 +56,35 @@ public function handle()
5656 $ this ->info ('Dumped schema ' );
5757 }
5858
59+ private static function reorderMigrationRows (array $ output ) : array
60+ {
61+ if (config ('migration-snapshot.reorder ' )) {
62+ $ reordered = [];
63+ $ new_id = 1 ;
64+ foreach ($ output as $ line ) {
65+ // Extract parts of "INSERT ... VALUES ([id],'[ver]',[batch])
66+ // where version begins with "YYYY_MM_DD_HHMMSS".
67+ $ occurrences = preg_match (
68+ "/^(.*?VALUES\s*)\([0-9]+,\s*'([0-9_]{17})(.*?),\s*[0-9]+\s*\)\s*;\s*$/iu " ,
69+ $ line ,
70+ $ m
71+ );
72+ if (1 !== $ occurrences ) {
73+ throw new \UnexpectedValueException (
74+ 'Only insert rows supported: ' . PHP_EOL . var_export ($ line , 1 )
75+ );
76+ }
77+ // Reassemble parts with new values and index by timestamp of
78+ // version string to sort.
79+ $ reordered [$ m [2 ]] = "$ m [1 ]( $ new_id,' $ m [2 ]$ m [3 ],0); " ;
80+ $ new_id += 1 ;
81+ }
82+ return $ reordered ;
83+ }
84+
85+ return $ output ;
86+ }
87+
5988 /**
6089 * @param array $db_config like ['host' => , 'port' => ].
6190 * @param string $schema_sql_path like '.../schema.sql'
@@ -101,13 +130,22 @@ private static function mysqlDump(array $db_config, string $schema_sql_path) : i
101130 }
102131
103132 // Include migration rows to avoid unnecessary reruns conflicting.
104- // CONSIDER: How this could be done as consistent snapshot with
105- // dump of structure, and avoid duplicate "SET" comments.
106- passthru (
107- $ command_prefix . ' migrations --no-create-info --skip-extended-insert >> '
108- . escapeshellarg ($ schema_sql_path ),
133+ exec (
134+ $ command_prefix . ' migrations --no-create-info --skip-extended-insert --compact ' ,
135+ $ output ,
109136 $ exit_code
110137 );
138+ if (0 !== $ exit_code ) {
139+ return $ exit_code ;
140+ }
141+
142+ $ output = self ::reorderMigrationRows ($ output );
143+
144+ file_put_contents (
145+ $ schema_sql_path ,
146+ implode (PHP_EOL , $ output ),
147+ FILE_APPEND
148+ );
111149
112150 return $ exit_code ;
113151 }
@@ -130,7 +168,6 @@ private static function pgsqlDump(array $db_config, string $schema_sql_path) : i
130168 . ' --port= ' . escapeshellarg ($ db_config ['port ' ])
131169 . ' --username= ' . escapeshellarg ($ db_config ['username ' ])
132170 . ' ' . escapeshellarg ($ db_config ['database ' ]);
133- // TODO: Suppress warning about insecure password.
134171 passthru (
135172 $ command_prefix
136173 . ' --file= ' . escapeshellarg ($ schema_sql_path )
@@ -142,13 +179,22 @@ private static function pgsqlDump(array $db_config, string $schema_sql_path) : i
142179 }
143180
144181 // Include migration rows to avoid unnecessary reruns conflicting.
145- // CONSIDER: How this could be done as consistent snapshot with
146- // dump of structure, and avoid duplicate "SET" comments.
147- passthru (
148- $ command_prefix . ' --table=migrations --data-only --inserts >> '
149- . escapeshellarg ($ schema_sql_path ),
182+ exec (
183+ $ command_prefix . ' --table=migrations --data-only --inserts ' ,
184+ $ output ,
150185 $ exit_code
151186 );
187+ if (0 !== $ exit_code ) {
188+ return $ exit_code ;
189+ }
190+
191+ $ output = self ::reorderMigrationRows ($ output );
192+
193+ file_put_contents (
194+ $ schema_sql_path ,
195+ implode (PHP_EOL , $ output ),
196+ FILE_APPEND
197+ );
152198
153199 return $ exit_code ;
154200 }
@@ -167,24 +213,40 @@ private static function sqliteDump(array $db_config, string $schema_sql_path) :
167213 // Since Sqlite lacks Information Schema, and dumping everything may be
168214 // too slow or memory intense, just query tables and dump them
169215 // individually.
216+ // CONSIDER: Using Laravel's `Schema` code instead.
170217 exec ($ command_prefix . ' .tables ' , $ output , $ exit_code );
171218 if (0 !== $ exit_code ) {
172219 return $ exit_code ;
173220 }
174221 $ tables = preg_split ('/\s+/ ' , implode (' ' , $ output ));
175222
223+ file_put_contents ($ schema_sql_path , '' );
224+
176225 foreach ($ tables as $ table ) {
177226 // Only migrations should dump data with schema.
178227 $ sql_command = 'migrations ' === $ table ? '.dump ' : '.schema ' ;
179228
180- passthru (
181- $ command_prefix . ' ' . escapeshellarg ("$ sql_command $ table " )
182- . ' >> ' . escapeshellarg ($ schema_sql_path ),
229+ $ output = [];
230+ exec (
231+ $ command_prefix . ' ' . escapeshellarg ("$ sql_command $ table " ),
232+ $ output ,
183233 $ exit_code
184234 );
185235 if (0 !== $ exit_code ) {
186236 return $ exit_code ;
187237 }
238+
239+ if ('migrations ' === $ table ) {
240+ $ insert_rows = array_slice ($ output , 4 , -1 );
241+ $ sorted = self ::reorderMigrationRows ($ insert_rows );
242+ array_splice ($ output , 4 , -1 , $ sorted );
243+ }
244+
245+ file_put_contents (
246+ $ schema_sql_path ,
247+ implode (PHP_EOL , $ output ) . PHP_EOL ,
248+ FILE_APPEND
249+ );
188250 }
189251
190252 return $ exit_code ;
0 commit comments