265 lines
10 KiB
PHP
265 lines
10 KiB
PHP
#!/usr/bin/env php
|
|
<?php
|
|
|
|
/**
|
|
* Regenerate tools/ci-controller-to-laravel-mapping.csv by comparing
|
|
* CodeIgniter app/Controllers with Laravel app/Http/Controllers.
|
|
*
|
|
* Usage:
|
|
* php tools/generate-ci-controller-mapping.php
|
|
* php tools/generate-ci-controller-mapping.php --ci-path=/path/to/app_codeigniter/app/Controllers
|
|
* php tools/generate-ci-controller-mapping.php --output=/path/to/out.csv
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
$laravelRoot = dirname(__DIR__);
|
|
$defaultCiRoot = dirname($laravelRoot) . DIRECTORY_SEPARATOR . 'app_codeigniter' . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'Controllers';
|
|
$defaultOutput = $laravelRoot . DIRECTORY_SEPARATOR . 'tools' . DIRECTORY_SEPARATOR . 'ci-controller-to-laravel-mapping.csv';
|
|
|
|
$options = getopt('', ['ci-path:', 'output:', 'help']);
|
|
if (isset($options['help'])) {
|
|
fwrite(STDOUT, <<<TXT
|
|
Generate CI → Laravel controller mapping CSV.
|
|
|
|
Options:
|
|
--ci-path=PATH CodeIgniter Controllers directory (default: sibling app_codeigniter/.../Controllers)
|
|
--output=PATH Output CSV path (default: tools/ci-controller-to-laravel-mapping.csv)
|
|
--help Show this message
|
|
|
|
TXT);
|
|
exit(0);
|
|
}
|
|
|
|
$ciRoot = isset($options['ci-path']) ? $options['ci-path'] : $defaultCiRoot;
|
|
$outputPath = isset($options['output']) ? $options['output'] : $defaultOutput;
|
|
|
|
if (! is_dir($ciRoot)) {
|
|
fwrite(STDERR, "CI controllers directory not found: {$ciRoot}\n");
|
|
exit(1);
|
|
}
|
|
|
|
$lvControllersDir = $laravelRoot . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'Http' . DIRECTORY_SEPARATOR . 'Controllers';
|
|
if (! is_dir($lvControllersDir)) {
|
|
fwrite(STDERR, "Laravel controllers directory not found: {$lvControllersDir}\n");
|
|
exit(1);
|
|
}
|
|
|
|
/** @var array<string, array{paths: string[], notes: string}> */
|
|
$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<string, string[]> 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");
|