Mercurial > packages > magicforger
diff src/Helpers/RelationshipNavigator.php @ 24:31109c61ce02 codex
Refactor RelationshipNavigator formatting and implement belongsTo, hasMany, belongsToMany injection in ModelGenerator
| author | Luka Sitas <sitas.luka.97@gmail.com> |
|---|---|
| date | Tue, 22 Apr 2025 21:37:44 -0400 |
| parents | 827efbf4d73c |
| children |
line wrap: on
line diff
--- a/src/Helpers/RelationshipNavigator.php Fri Apr 11 20:50:20 2025 -0400 +++ b/src/Helpers/RelationshipNavigator.php Tue Apr 22 21:37:44 2025 -0400 @@ -4,33 +4,39 @@ use Illuminate\Support\Facades\DB; +/** + * Class RelationshipNavigator + * + * This class is responsible for navigating database table relationships, specifically + * identifying and categorizing 'belongsTo', 'hasMany', and 'hasManyThrough' relationships. + */ class RelationshipNavigator { + /** + * Handles the retrieval and display of table relationships. + * + * @return void + */ public static function handle() { $tables = DB::select('SHOW TABLES'); - $tableNames = array_map(function ($table) { - return current((array) $table); - }, $tables); + $tableNames = array_map(fn($table) => 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) { + + foreach ($relations as $relation => $relatedTables) { + echo "$relation: \n"; + foreach ($relatedTables as $relatedTable) { echo "\t"; - foreach ($related_table as $key => $value) { - echo "$key : "; + foreach ($relatedTable as $key => $value) { if (is_array($value)) { - foreach ($related_table as $key => $value) { - echo "\n\t\t"; - echo "$key: $value"; - } + echo "\n\t\t" . implode("\n\t\t", array_map(fn($k, $v) => "$k: $v", array_keys($value), $value)); } else { - echo $value.' '; + echo "$key: $value "; } } echo "\n"; @@ -40,6 +46,12 @@ } } + /** + * Retrieves relationships of a specific table. + * + * @param string $table The table name. + * @return array An array containing 'belongsTo', 'hasMany', and 'hasManyThrough' relations. + */ public static function getRelations($table) { $relations = [ @@ -51,11 +63,11 @@ $foreignKeys = DB::select("SHOW KEYS FROM $table WHERE Key_name != 'PRIMARY'"); $referencedTables = self::getAllReferencedTables($table); - // BelongsTo Relationships + // Determine 'belongsTo' Relationships foreach ($foreignKeys as $fk) { $column = $fk->Column_name; - // skip created and updated by + // Skip certain columns if (in_array($column, ['created_by', 'updated_by'])) { continue; } @@ -65,17 +77,16 @@ if ($referencedTable) { $relations['belongsTo'][] = ['column' => $column, 'table' => $referencedTable->REFERENCED_TABLE_NAME]; } - } - // HasMany Relationships + // Determine 'hasMany' Relationships if ($reverseRelation = self::findReverseRelation($table)) { foreach ($reverseRelation as $relatedTable) { $relations['hasMany'][] = $relatedTable; } } - // HasManyThrough Relationships + // Determine 'hasManyThrough' Relationships if ($hasManyThroughRelations = self::findHasManyThroughRelations($table)) { foreach ($hasManyThroughRelations as $relatedTable) { $relations['hasManyThrough'][] = $relatedTable; @@ -85,121 +96,137 @@ return $relations; } + /** + * Retrieves all referenced tables for a given table. + * + * @param string $table The table name. + * @return array|null An associative array of referenced tables, keyed by column name. + */ 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' - "); + AND REFERENCED_TABLE_NAME IS NOT NULL + AND TABLE_NAME = ? + ", [$table]); - $tables = self::re_key_array($results, 'COLUMN_NAME'); - - return (count($tables) > 0) ? $tables : null; + return self::re_key_array($results, 'COLUMN_NAME') ?: null; } + /** + * Finds 'hasMany' inverse relationships for a given table. + * + * @param string $table The table name. + * @return array|null An array of related tables with column names. + */ 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_TABLE_NAME = ? AND REFERENCED_COLUMN_NAME = 'id' - AND COLUMN_NAME != 'created_by' - AND COLUMN_NAME != 'updated_by' - "); + AND COLUMN_NAME NOT IN ('created_by', 'updated_by') + ", [$table]); - $relatedTables = array_map(function ($rel) { - return ['table' => $rel->TABLE_NAME, 'column' => $rel->COLUMN_NAME]; - }, $relations); - - return $relatedTables ? $relatedTables : null; + return array_map(fn($rel) => ['table' => $rel->TABLE_NAME, 'column' => $rel->COLUMN_NAME], $relations) ?: null; } - + + /** + * Finds 'hasManyThrough' relationships for a given table. + * + * @param string $table The table name. + * @return array An array of 'hasManyThrough' relationships. + */ public static function findHasManyThroughRelations($table) { $relations = []; - - // Find potential intermediary tables $intermediaryTables = self::findReverseRelation($table); - if (! is_null($intermediaryTables)) { - + if ($intermediaryTables !== null) { foreach ($intermediaryTables as $intermediary) { - - if ($is_pivot = self::isPivot($intermediary['table'])) { - $is_pivot = current($is_pivot); + if ($isPivot = self::isPivot($intermediary['table'])) { + $isPivot = current($isPivot); - // 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]]; + $potentialTables = array_keys($isPivot['tables']); + $externalTable = $potentialTables[0] === $table ? $isPivot['tables'][$potentialTables[1]] : $isPivot['tables'][$potentialTables[0]]; + $internalTable = $potentialTables[0] === $table ? $isPivot['tables'][$potentialTables[0]] : $isPivot['tables'][$potentialTables[1]]; - $hasManyThrough = [ - 'table' => $external_table['table_name'], - 'through' => [ - 'table' => $is_pivot['table'], - 'external_column' => $external_table['column'], - 'internal_column' => $internal_table['column'] - ] + $hasManyThrough = [ + 'table' => $externalTable['table_name'], + 'through' => [ + 'table' => $isPivot['table'], + 'external_column' => $externalTable['column'], + 'internal_column' => $internalTable['column'], + ], ]; $relations[] = $hasManyThrough; } } - } return $relations; } + /** + * Determines if a table is a pivot table. + * + * @param string $table The table name. + * @return array|null An array with pivot details or null if not a pivot. + */ 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 != '' - "); + SELECT TABLE_NAME, TABLE_COMMENT + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = ? + AND TABLE_COMMENT != '' + ", [$table]); - if(!is_null($pivotTables) && count($pivotTables) > 0) { - $ref = current($pivotTables); - - $pivots = json_decode(str_replace('PIVOT:', '', $ref->TABLE_COMMENT), true); + if (!is_null($pivotTables) && count($pivotTables) > 0) { + $ref = current($pivotTables); + $pivots = json_decode(str_replace('PIVOT:', '', $ref->TABLE_COMMENT), true); + $tables = []; - $tables = []; - if (count($pivots) > 0) { - //re-key array - $references = self::getAllReferencedTables($table); - $references = self::re_key_array($references, 'REFERENCED_TABLE_NAME'); + if (count($pivots) > 0) { + $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]; - } + foreach ($pivots as $key => $value) { + if ($refData = ($references[$value] ?? null)) { + $tables[$value] = [ + 'table_name' => $value, + 'column' => $refData->COLUMN_NAME, + ]; + } + } + } + $relations[] = ['table' => $ref->TABLE_NAME, 'tables' => $tables]; + } - return $relations != [] ? $relations : null; + return !empty($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; - } + /** + * Re-keys an array of objects using a specific object's property. + * + * @param array $oldArray The original array of objects. + * @param string $key The key to re-index by. + * @return array The re-keyed array. + */ + public static function re_key_array($oldArray, $key) + { + $newArray = []; + if (count($oldArray) > 0) { + foreach ($oldArray as $array) { + $newArray[$array->$key] = $array; + } + } + return $newArray; + } }
