#!/usr/bin/env php */ $explicit = [ 'AdminProgressController' => ['paths' => ['Api/ClassProgress/ClassProgressController.php'], 'notes' => ''], 'ParentProgressController' => ['paths' => ['Api/ClassProgress/ClassProgressController.php'], 'notes' => ''], 'ParentReportCardController' => ['paths' => ['Api/Reports/ReportCardsController.php'], 'notes' => ''], 'ApiDocsController' => ['paths' => ['Api/Documentation/ApiDocsAdminController.php'], 'notes' => ''], 'DocsController' => [ 'paths' => ['Api/Documentation/DocsCatalogController.php', 'Api/Documentation/ApiDocsAdminController.php'], 'notes' => 'Two CI files (root + View); docs split between catalog + admin', ], 'ConfigurationController' => ['paths' => ['Api/Settings/ConfigurationAdminController.php'], 'notes' => ''], 'ClassPrepController' => ['paths' => ['Api/ClassPreparation/ClassPreparationController.php'], 'notes' => ''], 'BadgesController' => ['paths' => ['Api/Badges/BadgeController.php'], 'notes' => ''], 'NotificationsController' => ['paths' => ['Api/Notifications/NotificationController.php'], 'notes' => ''], 'FlagController' => ['paths' => ['Api/Incidents/IncidentController.php'], 'notes' => ''], 'SendSMSController' => ['paths' => ['Api/Messaging/MessagesController.php'], 'notes' => ''], 'TestDBController' => [ 'paths' => ['Api/System/DatabaseHealthController.php', 'Api/System/HealthController.php'], 'notes' => '', ], 'ErrorController' => ['paths' => ['Api/System/AccessDeniedController.php'], 'notes' => ''], 'ScorePredictor' => ['paths' => ['Api/Scores/ScorePredictorController.php'], 'notes' => ''], 'CompetitionWinnersController' => ['paths' => ['Api/Public/PublicWinnersController.php'], 'notes' => ''], 'WinnersController' => ['paths' => ['Api/Public/PublicWinnersController.php'], 'notes' => ''], 'AssignmentController' => ['paths' => ['Api/Assignment/AssignmentApiController.php'], 'notes' => ''], 'Home' => ['paths' => [], 'notes' => 'CI welcome_message only; Laravel SPA + API'], 'BaseController' => ['paths' => [], 'notes' => 'CI framework base'], 'PrintablesBaseController' => ['paths' => [], 'notes' => 'Abstract printable base (CI)'], 'InitializeRolesPermissions' => ['paths' => [], 'notes' => 'Use Laravel seeds/Artisan; not an HTTP controller'], 'PrintRequests' => [ 'paths' => ['Api/PrintRequests/PrintRequestsController.php'], 'notes' => 'HTTP JSON API + PrintRequestsPortalService', ], 'RFIDController' => [ 'paths' => [ 'Api/BadgeScan/BadgeScanController.php', 'Api/Students/StudentController.php', ], 'notes' => 'Scan + logs: BadgeScanController; assign student badge: StudentController.updateBadgeScan', ], 'AdministratorController' => [ 'paths' => [ 'Api/Administrator/AdministratorAbsenceController.php', 'Api/Administrator/AdministratorDashboardController.php', 'Api/Administrator/AdministratorEnrollmentController.php', 'Api/Administrator/AdministratorNotificationController.php', 'Api/Administrator/AdministratorTeacherSubmissionController.php', 'Api/Administrator/EmergencyContactController.php', 'Api/Administrator/TeacherClassAssignmentController.php', ], 'notes' => 'Large CI controller split across Laravel admin APIs', ], 'AttendanceController' => [ 'paths' => [ 'Api/Attendance/AdminAttendanceApiController.php', 'Api/Attendance/StaffAttendanceApiController.php', 'Api/Attendance/TeacherAttendanceApiController.php', ], 'notes' => 'Attendance UI split by role in Laravel API', ], ]; /** @return array basename => list of relative paths under Http/Controllers */ function indexLaravelControllers(string $controllersDir): array { $map = []; $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($controllersDir, FilesystemIterator::SKIP_DOTS) ); $prefixLen = strlen($controllersDir) + 1; foreach ($iterator as $fileInfo) { /** @var SplFileInfo $fileInfo */ if (! $fileInfo->isFile() || strcasecmp($fileInfo->getExtension(), 'php') !== 0) { continue; } if ($fileInfo->getFilename() === 'Controller.php') { continue; } $full = $fileInfo->getPathname(); $rel = str_replace('\\', '/', substr($full, $prefixLen)); $base = $fileInfo->getBasename('.php'); if (! isset($map[$base])) { $map[$base] = []; } $map[$base][] = $rel; } return $map; } /** @param string[] $paths */ function joinRepoPaths(array $paths): string { $prefixed = array_map( static fn (string $p): string => 'app/Http/Controllers/'.$p, array_filter($paths) ); return implode('|', $prefixed); } function resolvePaths(string $basename, array $explicit, array $lvFiles): array { if (isset($explicit[$basename])) { return $explicit[$basename]; } if (isset($lvFiles[$basename])) { return ['paths' => $lvFiles[$basename], 'notes' => '']; } return ['paths' => [], 'notes' => 'NOT FOUND IN Laravel app/Http/Controllers']; } function migrationStatus(string $basename, array $resolved, array $explicit, array $lvFiles): string { if (isset($explicit[$basename])) { $e = $explicit[$basename]; if ($basename === 'AdministratorController') { return 'mapped_split'; } if ($basename === 'AttendanceController') { return 'mapped_split'; } if ($basename === 'RFIDController') { return 'mapped_split'; } if ($basename === 'Home') { return 'stub_replaced'; } if (in_array($basename, ['BaseController', 'PrintablesBaseController'], true)) { return 'framework_base'; } if ($basename === 'InitializeRolesPermissions') { return 'setup_script'; } if ($e['paths'] === []) { return 'no_laravel_controller'; } if ($basename === 'DocsController') { return 'mapped_renamed'; } $renamed = [ 'AdminProgressController', 'ParentProgressController', 'ParentReportCardController', 'ApiDocsController', 'ConfigurationController', 'ClassPrepController', 'BadgesController', 'NotificationsController', 'FlagController', 'SendSMSController', 'TestDBController', 'ErrorController', 'ScorePredictor', 'CompetitionWinnersController', 'WinnersController', 'AssignmentController', 'PrintRequests', ]; if (in_array($basename, $renamed, true)) { return 'mapped_renamed'; } return 'mapped_explicit'; } if (isset($lvFiles[$basename])) { return count($lvFiles[$basename]) > 1 ? 'ambiguous_duplicate_in_laravel' : 'mapped_exact'; } return 'unmapped'; } $lvFiles = indexLaravelControllers($lvControllersDir); $ciFiles = []; $ciIterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($ciRoot, FilesystemIterator::SKIP_DOTS) ); $ciPrefixLen = strlen($ciRoot) + 1; foreach ($ciIterator as $fileInfo) { if (! $fileInfo->isFile() || strcasecmp($fileInfo->getExtension(), 'php') !== 0) { continue; } $full = $fileInfo->getPathname(); $rel = str_replace('\\', '/', substr($full, $ciPrefixLen)); $ciFiles[$full] = $rel; } ksort($ciFiles); $rows = []; foreach ($ciFiles as $full => $relPath) { $basename = basename($full, '.php'); $resolved = resolvePaths($basename, $explicit, $lvFiles); $pathStr = joinRepoPaths($resolved['paths']); $notes = $resolved['notes']; $status = migrationStatus($basename, $resolved, $explicit, $lvFiles); if ($status === 'unmapped') { $pathStr = ''; if ($notes === '') { $notes = 'NOT FOUND IN Laravel app/Http/Controllers'; } } $rows[] = [$relPath, $basename, $pathStr, $status, $notes]; } $dir = dirname($outputPath); if (! is_dir($dir)) { mkdir($dir, 0775, true); } $fh = fopen($outputPath, 'wb'); if ($fh === false) { fwrite(STDERR, "Cannot write: {$outputPath}\n"); exit(1); } $headers = ['ci_relative_path', 'ci_basename', 'laravel_controller_paths_from_repo_root', 'migration_status', 'notes']; fputcsv($fh, $headers); foreach ($rows as $row) { fputcsv($fh, $row); } fclose($fh); fwrite(STDOUT, "Wrote ".count($rows)." rows to {$outputPath}\n");