|
11 | 11 | * @copyright Dennis Mozes |
12 | 12 | * @license GNU/LGPL License: http://www.gnu.org/copyleft/lgpl.html |
13 | 13 | * |
14 | | - * Modified by Raymond for use with this module |
| 14 | + * Modified by Raymond and Seiger for use with this module |
15 | 15 | * |
16 | 16 | **/ |
17 | 17 | class MysqlDumper implements MysqlDumperInterface |
@@ -82,14 +82,15 @@ public function createDump($callBack) |
82 | 82 | $databaseName = $dataBaseConfig['database']; |
83 | 83 |
|
84 | 84 | $sql = 'SELECT table_name AS "table", round(((data_length + index_length) / 1024 / 1024)) "size" FROM information_schema.TABLES WHERE table_schema = "'.$databaseName.'"'; |
85 | | - $tableSizes = array_column($modx->db->makeArray($modx->db->query($sql)),'size','table'); |
| 85 | + $tableSizes = array_column($modx->db->makeArray($modx->db->query($sql)), 'size', 'table'); |
| 86 | + |
| 87 | + // Sort tables by foreign key dependencies |
| 88 | + $tables = $this->sortTablesByDependencies($this->_dbtables); |
86 | 89 |
|
87 | 90 | // Set line feed |
88 | 91 | $lf = "\n"; |
89 | 92 | $tempfile_path = MODX_BASE_PATH . 'assets/backup/temp.php'; |
90 | 93 |
|
91 | | - $result = $modx->getDatabase()->query('SHOW TABLES'); |
92 | | - $tables = $this->result2Array(0, $result); |
93 | 94 | foreach ($tables as $tblval) { |
94 | 95 | $result = $modx->getDatabase()->query("SHOW CREATE TABLE `{$tblval}`"); |
95 | 96 | $createtable[$tblval] = $this->result2Array(1, $result); |
@@ -122,8 +123,6 @@ public function createDump($callBack) |
122 | 123 |
|
123 | 124 |
|
124 | 125 | foreach ($tables as $tblval) { |
125 | | - |
126 | | - |
127 | 126 | // check for selected table |
128 | 127 | if (isset($this->_dbtables)) { |
129 | 128 | if (strstr(",{$this->_dbtables},", ",{$tblval},") === false) { |
@@ -175,7 +174,7 @@ public function createDump($callBack) |
175 | 174 |
|
176 | 175 |
|
177 | 176 | while ($arr = $modx->getDatabase()->getRow($result)) { |
178 | | - //формируем блок значений |
| 177 | + //формируем блок значений |
179 | 178 | $insertdump = "("; |
180 | 179 | if (!is_array($arr)) $arr = array(); |
181 | 180 |
|
@@ -309,4 +308,82 @@ public function setSnapshotFile($file){ |
309 | 308 | $this->snapshootFile = $file; |
310 | 309 | } |
311 | 310 |
|
| 311 | + /** |
| 312 | + * Sorts the tables based on their foreign key dependencies. |
| 313 | + * |
| 314 | + * This method sorts the given list of tables in a way that ensures tables with no dependencies (or primary tables) |
| 315 | + * are processed first, followed by tables that depend on other tables through foreign keys. |
| 316 | + * It uses a topological sorting approach to ensure that tables with dependencies are created in the correct order. |
| 317 | + * The method relies on the **getForeignKeyDependencies()** method to retrieve the dependencies of each table. |
| 318 | + * |
| 319 | + * @param array $dbtables An array of table names to be sorted based on their dependencies. |
| 320 | + * |
| 321 | + * @return array The sorted array of table names, with dependent tables placed after the ones they rely on. |
| 322 | + */ |
| 323 | + public function sortTablesByDependencies($dbtables) |
| 324 | + { |
| 325 | + $sorted = []; |
| 326 | + $visited = []; |
| 327 | + $dependencies = $this->getForeignKeyDependencies($dbtables); |
| 328 | + |
| 329 | + foreach ($dbtables as $table) { |
| 330 | + $this->visitTable($table, $dependencies, $visited, $sorted); |
| 331 | + } |
| 332 | + |
| 333 | + return $sorted; |
| 334 | + } |
| 335 | + |
| 336 | + /** |
| 337 | + * Retrieves all foreign key dependencies for the given tables. |
| 338 | + * Returns an associative array with tables and their dependencies. |
| 339 | + */ |
| 340 | + public function getForeignKeyDependencies($tables) |
| 341 | + { |
| 342 | + $dependencies = []; |
| 343 | + |
| 344 | + foreach ($tables as $table) { |
| 345 | + $sql = "SHOW CREATE TABLE `$table`"; |
| 346 | + $result = evo()->db->query($sql); |
| 347 | + $createTableQuery = evo()->db->getRow($result)['Create Table']; |
| 348 | + preg_match_all('/FOREIGN KEY \(`([^`]+)`\) REFERENCES `([^`]+)` \(`([^`]+)`\)/', $createTableQuery, $matches); |
| 349 | + |
| 350 | + if (!empty($matches[2])) { |
| 351 | + foreach ($matches[2] as $index => $referencedTable) { |
| 352 | + $dependencies[$table][] = $referencedTable; |
| 353 | + } |
| 354 | + } |
| 355 | + } |
| 356 | + |
| 357 | + return $dependencies; |
| 358 | + } |
| 359 | + |
| 360 | + /** |
| 361 | + * Checks the table and its dependencies, visits all the tables it depends on, and adds them to the sorted list. |
| 362 | + * |
| 363 | + * This method recursively visits tables, checking their dependencies, and adds them to the **$sorted** array. |
| 364 | + * If a table has already been visited, it is skipped. |
| 365 | + * It works based on the principle of topological sorting to ensure the correct order of table creation |
| 366 | + * during the dump process, taking foreign keys into account. |
| 367 | + * |
| 368 | + * @param string $table The name of the table to check. |
| 369 | + * @param array $dependencies An associative array containing tables and their dependencies. |
| 370 | + * @param array $visited An array containing already visited tables to avoid circular references. |
| 371 | + * @param array $sorted An array where tables are added after visiting their dependencies. |
| 372 | + */ |
| 373 | + private function visitTable($table, $dependencies, &$visited, &$sorted) |
| 374 | + { |
| 375 | + if (isset($visited[$table])) { |
| 376 | + return; |
| 377 | + } |
| 378 | + |
| 379 | + $visited[$table] = true; |
| 380 | + |
| 381 | + if (isset($dependencies[$table])) { |
| 382 | + foreach ($dependencies[$table] as $dependentTable) { |
| 383 | + $this->visitTable($dependentTable, $dependencies, $visited, $sorted); |
| 384 | + } |
| 385 | + } |
| 386 | + |
| 387 | + $sorted[] = $table; |
| 388 | + } |
312 | 389 | } |
0 commit comments