@@ -129,6 +129,7 @@ private static function mysqlDump(array $db_config, string $schema_sql_path) : i
129129 return 1 ;
130130 }
131131 $ schema_sql = preg_replace ('/\s+AUTO_INCREMENT=[0-9]+/iu ' , '' , $ schema_sql );
132+ $ schema_sql = self ::trimUnderscoresFromForeign ($ schema_sql );
132133 if (false === file_put_contents ($ schema_sql_path , $ schema_sql )) {
133134 return 1 ;
134135 }
@@ -156,6 +157,55 @@ private static function mysqlDump(array $db_config, string $schema_sql_path) : i
156157 return $ exit_code ;
157158 }
158159
160+ /**
161+ * Trim underscores from FK constraint names to workaround PTOSC quirk.
162+ *
163+ * @param string $sql like "CONSTRAINT _my_fk FOREIGN KEY ..."
164+ *
165+ * @return string without leading underscores like "CONSTRAINT my_fk ...".
166+ */
167+ public static function trimUnderscoresFromForeign (string $ sql ) : string
168+ {
169+ if (! config ('migration-snapshot.trim-underscores ' )) {
170+ return $ sql ;
171+ }
172+
173+ $ trimmed = preg_replace (
174+ '/(^|,)(\s*CONSTRAINT\s+[`"]?)_+(.*?[`"]?\s+FOREIGN\s+KEY\b.*)/imu ' ,
175+ '\1\2\3 ' ,
176+ $ sql
177+ );
178+
179+ // Reorder constraints for consistency since dump put underscored first.
180+ $ offset = 0 ;
181+ // Sort each adjacent block of constraints.
182+ while (preg_match ('/((?:^|,)?\s*CONSTRAINT\s+.*?(?:,|\)\s*\)))+/imu ' , $ trimmed , $ m , PREG_OFFSET_CAPTURE , $ offset )) {
183+ // Bump offset to avoid unintentionally reprocessing already sorted.
184+ $ offset = $ m [count ($ m ) - 1 ][1 ] + strlen ($ m [count ($ m ) - 1 ][0 ]);
185+ $ constraints_original = $ m [0 ][0 ];
186+ if (! preg_match_all ('/(?:^|,)\s*CONSTRAINT\s+.*?(?:,|\)\s*\))/imu ' , $ constraints_original , $ m )) {
187+ continue ;
188+ }
189+ $ constraints_array = $ m [0 ];
190+ foreach ($ constraints_array as &$ constraint ) {
191+ $ constraint = trim ($ constraint , ", \r\n" );
192+ // Trim extra parenthesis at the end of table definitions.
193+ $ constraint = preg_replace ('/(\s*\))\s*\)\z/imu ' , '\1 ' , $ constraint , 1 );
194+ }
195+ sort ($ constraints_array );
196+ $ separator = ', ' . PHP_EOL ;
197+ // Comma or "\n)".
198+ $ terminator = preg_match ('/(,|\s*\))\z/imu ' , $ constraints_original , $ m )
199+ ? $ m [1 ] : '' ;
200+ $ constraints_sorted = $ separator
201+ . implode ($ separator , $ constraints_array )
202+ . $ terminator ;
203+ $ trimmed = str_replace ($ constraints_original , $ constraints_sorted , $ trimmed );
204+ }
205+
206+ return $ trimmed ;
207+ }
208+
159209 /**
160210 * @param array $db_config like ['host' => , 'port' => ].
161211 *
0 commit comments