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