Mercurial > packages > magicforger
view src/Helpers/RelationshipNavigator.php @ 23:827efbf4d73c main-dev
Huge changes to the relationships for models and more complex
| author | Luka Sitas <sitas.luka.97@gmail.com> |
|---|---|
| date | Fri, 11 Apr 2025 20:50:20 -0400 |
| parents | |
| children | 31109c61ce02 |
line wrap: on
line source
<?php namespace Wizard\MagicForger\Helpers; use Illuminate\Support\Facades\DB; class RelationshipNavigator { public static function handle() { $tables = DB::select('SHOW TABLES'); $tableNames = array_map(function ($table) { return current((array) $table); }, $tables); foreach ($tableNames as $table) { echo "Table: $table \n"; $relations = self::getRelations($table); echo "Relationships: \n"; foreach ($relations as $relation => $related_tables) { echo $relation.": \n"; foreach ($related_tables as $related_table) { echo "\t"; foreach ($related_table as $key => $value) { echo "$key : "; if (is_array($value)) { foreach ($related_table as $key => $value) { echo "\n\t\t"; echo "$key: $value"; } } else { echo $value.' '; } } echo "\n"; } } echo "\n --- \n"; } } public static function getRelations($table) { $relations = [ 'belongsTo' => [], 'hasMany' => [], 'hasManyThrough' => [], ]; $foreignKeys = DB::select("SHOW KEYS FROM $table WHERE Key_name != 'PRIMARY'"); $referencedTables = self::getAllReferencedTables($table); // BelongsTo Relationships foreach ($foreignKeys as $fk) { $column = $fk->Column_name; // skip created and updated by if (in_array($column, ['created_by', 'updated_by'])) { continue; } $referencedTable = $referencedTables[$column] ?? null; if ($referencedTable) { $relations['belongsTo'][] = ['column' => $column, 'table' => $referencedTable->REFERENCED_TABLE_NAME]; } } // HasMany Relationships if ($reverseRelation = self::findReverseRelation($table)) { foreach ($reverseRelation as $relatedTable) { $relations['hasMany'][] = $relatedTable; } } // HasManyThrough Relationships if ($hasManyThroughRelations = self::findHasManyThroughRelations($table)) { foreach ($hasManyThroughRelations as $relatedTable) { $relations['hasManyThrough'][] = $relatedTable; } } return $relations; } public static function getAllReferencedTables($table) { $results = DB::select(" SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '$table' "); $tables = self::re_key_array($results, 'COLUMN_NAME'); return (count($tables) > 0) ? $tables : null; } public static function findReverseRelation($table) { $relations = DB::select(" SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME = '$table' AND REFERENCED_COLUMN_NAME = 'id' AND COLUMN_NAME != 'created_by' AND COLUMN_NAME != 'updated_by' "); $relatedTables = array_map(function ($rel) { return ['table' => $rel->TABLE_NAME, 'column' => $rel->COLUMN_NAME]; }, $relations); return $relatedTables ? $relatedTables : null; } public static function findHasManyThroughRelations($table) { $relations = []; // Find potential intermediary tables $intermediaryTables = self::findReverseRelation($table); if (! is_null($intermediaryTables)) { foreach ($intermediaryTables as $intermediary) { if ($is_pivot = self::isPivot($intermediary['table'])) { $is_pivot = current($is_pivot); // reformat the table based on the current and external $potential_tables = array_keys($is_pivot['tables']); $external_table = $potential_tables[0] == $table ? $is_pivot['tables'][$potential_tables[1]] : $is_pivot['tables'][$potential_tables[0]]; $internal_table = $potential_tables[0] == $table ? $is_pivot['tables'][$potential_tables[0]] : $is_pivot['tables'][$potential_tables[1]]; $hasManyThrough = [ 'table' => $external_table['table_name'], 'through' => [ 'table' => $is_pivot['table'], 'external_column' => $external_table['column'], 'internal_column' => $internal_table['column'] ] ]; $relations[] = $hasManyThrough; } } } return $relations; } public static function isPivot($table) { $relations = []; // TODO: alsot get the columns that are relevant $pivotTables = DB::select(" SELECT TABLE_NAME, TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '{$table}' AND TABLE_COMMENT != '' "); if(!is_null($pivotTables) && count($pivotTables) > 0) { $ref = current($pivotTables); $pivots = json_decode(str_replace('PIVOT:', '', $ref->TABLE_COMMENT), true); $tables = []; if (count($pivots) > 0) { //re-key array $references = self::getAllReferencedTables($table); $references = self::re_key_array($references, 'REFERENCED_TABLE_NAME'); foreach($pivots as $key => $value) { if($ref_data = ($references[$value] ?? null)) { $tables[$value] = [ 'table_name' => $value, 'column' => $ref_data->COLUMN_NAME ]; } } } $relations[] = ['table' => $ref->TABLE_NAME, 'tables' => $tables]; } return $relations != [] ? $relations : null; } public static function re_key_array($old_array, $key) { $new_array = []; if (count($old_array) > 0) { foreach ($old_array as $array) { $new_array[$array->$key] = $array; } } return $new_array; } }
