diff --git a/common/framework/parsers/dbtableparser.php b/common/framework/parsers/dbtableparser.php index c4330d4ca..ab4866ec6 100644 --- a/common/framework/parsers/dbtableparser.php +++ b/common/framework/parsers/dbtableparser.php @@ -281,4 +281,71 @@ class DBTableParser extends BaseParser return $type; } } + + /** + * Order tables according to foreign key relations. + * + * @param array $tables [$table_name => $filename] + * @return array + */ + public static function resolveDependency(array $tables): array + { + // Compile the list of each table's dependency. + $ref_list = []; + $i = 0; + foreach ($tables as $table_name => $filename) + { + $table = self::loadXML($filename); + if ($table) + { + $info = (object)['name' => $table_name, 'refs' => [], 'index' => $i++]; + foreach ($table->constraints as $constraint) + { + if ($constraint->references) + { + $ref = explode('.', $constraint->references); + $info->refs[] = $ref[0]; + } + } + $ref_list[$table_name] = $info; + } + } + + // Sort each table after the ones they are dependent on. + for ($j = 0; $j < count($ref_list); $j++) + { + $changed = false; + foreach ($ref_list as $table_name => $info) + { + if (count($info->refs)) + { + foreach ($info->refs as $ref_name) + { + if (isset($ref_list[$ref_name]) && $info->index <= $ref_list[$ref_name]->index) + { + $info->index = $ref_list[$ref_name]->index + 1; + $changed = true; + } + } + } + $k++; + } + if (!$changed) + { + break; + } + } + + uasort($ref_list, function($a, $b) { + return $a->index - $b->index; + }); + + // Produce a result in the same format as the input. + $result = []; + foreach ($ref_list as $table_name => $info) + { + $result[$table_name] = $tables[$table_name]; + } + return $result; + } } diff --git a/modules/install/install.controller.php b/modules/install/install.controller.php index c72082c84..eb8a48652 100644 --- a/modules/install/install.controller.php +++ b/modules/install/install.controller.php @@ -530,7 +530,7 @@ class installController extends install // Create a table if the schema xml exists in the "schemas" directory of the module $schema_dir = sprintf('%s/schemas/', $module_path); $schema_files = FileHandler::readDir($schema_dir, NULL, false, true); - + $schema_sorted = []; foreach ($schema_files as $filename) { if (!preg_match('/\/([a-zA-Z0-9_]+)\.xml$/', $filename, $matches)) @@ -543,16 +543,24 @@ class installController extends install } $table_name = $matches[1]; - if($oDB->isTableExists($table_name)) + if(isset($schema_sorted[$table_name]) || $oDB->isTableExists($table_name)) { continue; } + + $schema_sorted[$table_name] = $filename; + } + + $schema_sorted = Rhymix\Framework\Parsers\DBTableParser::resolveDependency($schema_sorted); + foreach ($schema_sorted as $table_name => $filename) + { $output = $oDB->createTable($filename); if(!$output->toBool()) { throw new Exception(lang('msg_create_table_failed') . ': ' . $table_name . ': ' . $oDB->getError()->getMessage()); } } + // Create a table and module instance and then execute install() method unset($oModule); $oModule = ModuleModel::getModuleInstallClass($module);