Order table creation by foreign key dependency

This commit is contained in:
Kijin Sung 2022-01-27 21:20:51 +09:00
parent 72132b2e74
commit a9821b815d
2 changed files with 77 additions and 2 deletions

View file

@ -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;
}
}

View file

@ -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);