remove codeigniter
This commit is contained in:
@@ -1,106 +0,0 @@
|
||||
ci_relative_path,ci_basename,laravel_controller_paths_from_repo_root,migration_status,notes
|
||||
AdminProgressController.php,AdminProgressController,app/Http/Controllers/Api/ClassProgress/ClassProgressController.php,mapped_renamed,
|
||||
Admin/CompetitionWinnersController.php,CompetitionWinnersController,app/Http/Controllers/Api/Public/PublicWinnersController.php,mapped_renamed,
|
||||
ApiDocsController.php,ApiDocsController,app/Http/Controllers/Api/Documentation/ApiDocsAdminController.php,mapped_renamed,
|
||||
AuthController.php,AuthController,app/Http/Controllers/Api/Auth/AuthController.php,mapped_exact,
|
||||
BaseController.php,BaseController,,framework_base,"CI framework base"
|
||||
ClassProgressController.php,ClassProgressController,app/Http/Controllers/Api/ClassProgress/ClassProgressController.php,mapped_exact,
|
||||
DocsController.php,DocsController,app/Http/Controllers/Api/Documentation/DocsCatalogController.php|app/Http/Controllers/Api/Documentation/ApiDocsAdminController.php,mapped_renamed,"Two CI files (root + View); docs split between catalog + admin"
|
||||
ErrorController.php,ErrorController,app/Http/Controllers/Api/System/AccessDeniedController.php,mapped_renamed,
|
||||
Home.php,Home,,stub_replaced,"CI welcome_message only; Laravel SPA + API"
|
||||
InitializeRolesPermissions.php,InitializeRolesPermissions,,setup_script,"Use Laravel seeds/Artisan; not an HTTP controller"
|
||||
ParentProgressController.php,ParentProgressController,app/Http/Controllers/Api/ClassProgress/ClassProgressController.php,mapped_renamed,
|
||||
ParentReportCardController.php,ParentReportCardController,app/Http/Controllers/Api/Reports/ReportCardsController.php,mapped_renamed,
|
||||
PrintRequests.php,PrintRequests,app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php,mapped_renamed,"HTTP JSON API + PrintRequestsPortalService"
|
||||
ProofreadController.php,ProofreadController,app/Http/Controllers/Api/Utilities/ProofreadController.php,mapped_exact,
|
||||
TimeOffNotificationController.php,TimeOffNotificationController,app/Http/Controllers/Api/Staff/TimeOffNotificationController.php,mapped_exact,
|
||||
View/AdministratorController.php,AdministratorController,app/Http/Controllers/Api/Administrator/AdministratorAbsenceController.php|app/Http/Controllers/Api/Administrator/AdministratorDashboardController.php|app/Http/Controllers/Api/Administrator/AdministratorEnrollmentController.php|app/Http/Controllers/Api/Administrator/AdministratorNotificationController.php|app/Http/Controllers/Api/Administrator/AdministratorTeacherSubmissionController.php|app/Http/Controllers/Api/Administrator/EmergencyContactController.php|app/Http/Controllers/Api/Administrator/TeacherClassAssignmentController.php,mapped_split,"Large CI controller split across Laravel admin APIs"
|
||||
View/AssignmentController.php,AssignmentController,app/Http/Controllers/Api/Assignment/AssignmentApiController.php,mapped_renamed,
|
||||
View/AttendanceCommentTemplateController.php,AttendanceCommentTemplateController,app/Http/Controllers/Api/Attendance/AttendanceCommentTemplateController.php,mapped_exact,
|
||||
View/AttendanceController.php,AttendanceController,app/Http/Controllers/Api/Attendance/AdminAttendanceApiController.php|app/Http/Controllers/Api/Attendance/StaffAttendanceApiController.php|app/Http/Controllers/Api/Attendance/TeacherAttendanceApiController.php,mapped_split,"Attendance UI split by role in Laravel API"
|
||||
View/AttendanceTrackingController.php,AttendanceTrackingController,app/Http/Controllers/Api/AttendanceTracking/AttendanceTrackingController.php,mapped_exact,
|
||||
View/AuthorizedUsersController.php,AuthorizedUsersController,app/Http/Controllers/Api/Parents/AuthorizedUsersController.php,mapped_exact,
|
||||
View/BadgesController.php,BadgesController,app/Http/Controllers/Api/Badges/BadgeController.php,mapped_renamed,
|
||||
View/BroadcastEmailController.php,BroadcastEmailController,app/Http/Controllers/Api/Email/BroadcastEmailController.php,mapped_exact,
|
||||
View/ClassController.php,ClassController,app/Http/Controllers/Api/Classes/ClassController.php,mapped_exact,
|
||||
View/ClassPrepController.php,ClassPrepController,app/Http/Controllers/Api/ClassPreparation/ClassPreparationController.php,mapped_renamed,
|
||||
View/ClassPreparationController.php,ClassPreparationController,app/Http/Controllers/Api/ClassPreparation/ClassPreparationController.php,mapped_exact,
|
||||
View/CommunicationController.php,CommunicationController,app/Http/Controllers/Api/Communication/CommunicationController.php,mapped_exact,
|
||||
View/CompetitionScoresController.php,CompetitionScoresController,app/Http/Controllers/Api/CompetitionScores/CompetitionScoresController.php,mapped_exact,
|
||||
View/ConfigurationController.php,ConfigurationController,app/Http/Controllers/Api/Settings/ConfigurationAdminController.php,mapped_renamed,
|
||||
View/ContactController.php,ContactController,app/Http/Controllers/Api/Support/ContactController.php,mapped_exact,
|
||||
View/DashboardRedirectController.php,DashboardRedirectController,app/Http/Controllers/Api/System/DashboardRedirectController.php,mapped_exact,
|
||||
View/DiscountController.php,DiscountController,app/Http/Controllers/Api/Discounts/DiscountController.php,mapped_exact,
|
||||
View/DocsController.php,DocsController,app/Http/Controllers/Api/Documentation/DocsCatalogController.php|app/Http/Controllers/Api/Documentation/ApiDocsAdminController.php,mapped_renamed,"Two CI files (root + View); docs split between catalog + admin"
|
||||
View/EmailController.php,EmailController,app/Http/Controllers/Api/Email/EmailController.php,mapped_exact,
|
||||
View/EmailExtractorController.php,EmailExtractorController,app/Http/Controllers/Api/Email/EmailExtractorController.php,mapped_exact,
|
||||
View/EmergencyContactController.php,EmergencyContactController,app/Http/Controllers/Api/Administrator/EmergencyContactController.php,mapped_exact,
|
||||
View/EventController.php,EventController,app/Http/Controllers/Api/Settings/EventController.php,mapped_exact,
|
||||
View/ExamDraftController.php,ExamDraftController,app/Http/Controllers/Api/Exams/ExamDraftController.php,mapped_exact,
|
||||
View/ExpenseController.php,ExpenseController,app/Http/Controllers/Api/Expenses/ExpenseController.php,mapped_exact,
|
||||
View/ExtraChargesController.php,ExtraChargesController,app/Http/Controllers/Api/ExtraCharges/ExtraChargesController.php,mapped_exact,
|
||||
View/FamilyAdminController.php,FamilyAdminController,app/Http/Controllers/Api/Family/FamilyAdminController.php,mapped_exact,
|
||||
View/FamilyController.php,FamilyController,app/Http/Controllers/Api/Family/FamilyController.php,mapped_exact,
|
||||
View/FilesController.php,FilesController,app/Http/Controllers/Api/Reports/FilesController.php,mapped_exact,
|
||||
View/FinalController.php,FinalController,app/Http/Controllers/Api/Scores/FinalController.php,mapped_exact,
|
||||
View/FinancialController.php,FinancialController,app/Http/Controllers/Api/Finance/FinancialController.php,mapped_exact,
|
||||
View/FlagController.php,FlagController,app/Http/Controllers/Api/Incidents/IncidentController.php,mapped_renamed,
|
||||
View/FrontendController.php,FrontendController,app/Http/Controllers/Api/Frontend/FrontendController.php,mapped_exact,
|
||||
View/GradingController.php,GradingController,app/Http/Controllers/Api/Grading/GradingController.php,mapped_exact,
|
||||
View/HealthController.php,HealthController,app/Http/Controllers/Api/System/HealthController.php,mapped_exact,
|
||||
View/HomeworkController.php,HomeworkController,app/Http/Controllers/Api/Scores/HomeworkController.php,mapped_exact,
|
||||
View/HomeworkTrackingController.php,HomeworkTrackingController,app/Http/Controllers/Api/Grading/HomeworkTrackingController.php,mapped_exact,
|
||||
View/InfoIconController.php,InfoIconController,app/Http/Controllers/Api/Frontend/InfoIconController.php,mapped_exact,
|
||||
View/InventoryController.php,InventoryController,app/Http/Controllers/Api/Inventory/InventoryController.php,mapped_exact,
|
||||
View/InvoiceController.php,InvoiceController,app/Http/Controllers/Api/Finance/InvoiceController.php,mapped_exact,
|
||||
View/IpBanController.php,IpBanController,app/Http/Controllers/Api/Auth/IpBanController.php,mapped_exact,
|
||||
View/LandingPageController.php,LandingPageController,app/Http/Controllers/Api/Frontend/LandingPageController.php,mapped_exact,
|
||||
View/LateSlipLogsController.php,LateSlipLogsController,app/Http/Controllers/Api/Attendance/LateSlipLogsController.php,mapped_exact,
|
||||
View/MessagesController.php,MessagesController,app/Http/Controllers/Api/Messaging/MessagesController.php,mapped_exact,
|
||||
View/MidtermController.php,MidtermController,app/Http/Controllers/Api/Scores/MidtermController.php,mapped_exact,
|
||||
View/NavBuilderController.php,NavBuilderController,app/Http/Controllers/Api/System/NavBuilderController.php,mapped_exact,
|
||||
View/NotificationsController.php,NotificationsController,app/Http/Controllers/Api/Notifications/NotificationController.php,mapped_renamed,
|
||||
View/PageController.php,PageController,app/Http/Controllers/Api/Frontend/PageController.php,mapped_exact,
|
||||
View/ParentAttendanceReportController.php,ParentAttendanceReportController,app/Http/Controllers/Api/Parents/ParentAttendanceReportController.php,mapped_exact,
|
||||
View/ParentController.php,ParentController,app/Http/Controllers/Api/Parents/ParentController.php,mapped_exact,
|
||||
View/ParticipationController.php,ParticipationController,app/Http/Controllers/Api/Scores/ParticipationController.php,mapped_exact,
|
||||
View/PaymentController.php,PaymentController,app/Http/Controllers/Api/Finance/PaymentController.php,mapped_exact,
|
||||
View/PaymentNotificationController.php,PaymentNotificationController,app/Http/Controllers/Api/Finance/PaymentNotificationController.php,mapped_exact,
|
||||
View/PaymentTransactionController.php,PaymentTransactionController,app/Http/Controllers/Api/Finance/PaymentTransactionController.php,mapped_exact,
|
||||
View/PaypalTransactionsController.php,PaypalTransactionsController,app/Http/Controllers/Api/Finance/PaypalTransactionsController.php,mapped_exact,
|
||||
View/PolicyController.php,PolicyController,app/Http/Controllers/Api/Settings/PolicyController.php,mapped_exact,
|
||||
View/PreferencesController.php,PreferencesController,app/Http/Controllers/Api/Settings/PreferencesController.php,mapped_exact,
|
||||
View/PrintRequests.php,PrintRequests,app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php,mapped_renamed,"HTTP JSON API + PrintRequestsPortalService"
|
||||
View/PrintablesBaseController.php,PrintablesBaseController,,framework_base,"Abstract printable base (CI)"
|
||||
View/ProjectController.php,ProjectController,app/Http/Controllers/Api/Scores/ProjectController.php,mapped_exact,
|
||||
View/PurchaseOrderController.php,PurchaseOrderController,app/Http/Controllers/Api/Finance/PurchaseOrderController.php,mapped_exact,
|
||||
View/QuizController.php,QuizController,app/Http/Controllers/Api/Scores/QuizController.php,mapped_exact,
|
||||
View/RFIDController.php,RFIDController,app/Http/Controllers/Api/BadgeScan/BadgeScanController.php|app/Http/Controllers/Api/Students/StudentController.php,mapped_split,"Scan + logs: BadgeScanController; assign student badge: StudentController.updateBadgeScan"
|
||||
View/RefundController.php,RefundController,app/Http/Controllers/Api/Finance/RefundController.php,mapped_exact,
|
||||
View/RegisterController.php,RegisterController,app/Http/Controllers/Api/Auth/RegisterController.php,mapped_exact,
|
||||
View/ReimbursementController.php,ReimbursementController,app/Http/Controllers/Api/Finance/ReimbursementController.php,mapped_exact,
|
||||
View/ReportCardsController.php,ReportCardsController,app/Http/Controllers/Api/Reports/ReportCardsController.php,mapped_exact,
|
||||
View/RolePermissionController.php,RolePermissionController,app/Http/Controllers/Api/Auth/RolePermissionController.php,mapped_exact,
|
||||
View/RoleSwitcherController.php,RoleSwitcherController,app/Http/Controllers/Api/Auth/RoleSwitcherController.php,mapped_exact,
|
||||
View/SchoolCalendarController.php,SchoolCalendarController,app/Http/Controllers/Api/Settings/SchoolCalendarController.php,mapped_exact,
|
||||
View/ScoreCommentController.php,ScoreCommentController,app/Http/Controllers/Api/Scores/ScoreCommentController.php,mapped_exact,
|
||||
View/ScoreController.php,ScoreController,app/Http/Controllers/Api/Scores/ScoreController.php,mapped_exact,
|
||||
View/ScorePredictor.php,ScorePredictor,app/Http/Controllers/Api/Scores/ScorePredictorController.php,mapped_renamed,
|
||||
View/SendSMSController.php,SendSMSController,app/Http/Controllers/Api/Messaging/MessagesController.php,mapped_renamed,
|
||||
View/SessionTimeoutController.php,SessionTimeoutController,app/Http/Controllers/Api/Auth/SessionTimeoutController.php,mapped_exact,
|
||||
View/SettingsController.php,SettingsController,app/Http/Controllers/Api/Settings/SettingsController.php,mapped_exact,
|
||||
View/SlipPrinterController.php,SlipPrinterController,app/Http/Controllers/Api/Reports/SlipPrinterController.php,mapped_exact,
|
||||
View/StaffController.php,StaffController,app/Http/Controllers/Api/Staff/StaffController.php,mapped_exact,
|
||||
View/StatsController.php,StatsController,app/Http/Controllers/Api/System/StatsController.php,mapped_exact,
|
||||
View/StickersController.php,StickersController,app/Http/Controllers/Api/Reports/StickersController.php,mapped_exact,
|
||||
View/StudentController.php,StudentController,app/Http/Controllers/Api/Students/StudentController.php,mapped_exact,
|
||||
View/SubjectCurriculumController.php,SubjectCurriculumController,app/Http/Controllers/Api/Subjects/SubjectCurriculumController.php,mapped_exact,
|
||||
View/SupplierController.php,SupplierController,app/Http/Controllers/Api/Inventory/SupplierController.php,mapped_exact,
|
||||
View/SupplyCategoryController.php,SupplyCategoryController,app/Http/Controllers/Api/Inventory/SupplyCategoryController.php,mapped_exact,
|
||||
View/SupportController.php,SupportController,app/Http/Controllers/Api/Support/SupportController.php,mapped_exact,
|
||||
View/TeacherController.php,TeacherController,app/Http/Controllers/Api/Staff/TeacherController.php,mapped_exact,
|
||||
View/TestDBController.php,TestDBController,app/Http/Controllers/Api/System/DatabaseHealthController.php|app/Http/Controllers/Api/System/HealthController.php,mapped_renamed,
|
||||
View/UiController.php,UiController,app/Http/Controllers/Api/Ui/UiController.php,mapped_exact,
|
||||
View/UserController.php,UserController,app/Http/Controllers/Api/Users/UserController.php,mapped_exact,
|
||||
View/WhatsappController.php,WhatsappController,app/Http/Controllers/Api/Messaging/WhatsappController.php,mapped_exact,
|
||||
WinnersController.php,WinnersController,app/Http/Controllers/Api/Public/PublicWinnersController.php,mapped_renamed,
|
||||
|
@@ -1,264 +0,0 @@
|
||||
#!/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");
|
||||
@@ -1,169 +0,0 @@
|
||||
/**
|
||||
* Sync Laravel $fillable + $timestamps from CodeIgniter *Model.php (sibling app_codeigniter).
|
||||
* Run: node tools/sync_fillable_from_codeigniter.mjs
|
||||
*/
|
||||
import { readdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { join, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const laravelRoot = join(__dirname, "..");
|
||||
const workspaceRoot = join(laravelRoot, "..");
|
||||
const ciModelsDir = join(workspaceRoot, "app_codeigniter", "app", "Models");
|
||||
const laravelModelsDir = join(laravelRoot, "app", "Models");
|
||||
|
||||
const manualCiToLaravel = new Map([
|
||||
["SettingsModel.php", "Setting.php"],
|
||||
]);
|
||||
|
||||
/** CI models that must not sync (legacy duplicate of another model). */
|
||||
const skipCiBasenames = new Set([
|
||||
"FlagModel.php", // table `flag`; Laravel uses CurrentFlagModel → current_flag
|
||||
]);
|
||||
|
||||
const skipLaravel = new Set([
|
||||
"Teacher.php",
|
||||
"Communication.php",
|
||||
"EventCharge.php",
|
||||
"ClassModel.php",
|
||||
"Calendar.php",
|
||||
]);
|
||||
|
||||
function ciFileToLaravel(ciBasename) {
|
||||
if (manualCiToLaravel.has(ciBasename)) return manualCiToLaravel.get(ciBasename);
|
||||
const m = ciBasename.match(/^(.+)Model\.php$/);
|
||||
if (!m) return null;
|
||||
const base = m[1];
|
||||
if (base === "Parent" || base === "Class") return `${base}Model.php`;
|
||||
return `${base}.php`;
|
||||
}
|
||||
|
||||
/** Find array after `protected $allowedFields =` (flexible spacing). */
|
||||
function extractAllowedFieldsArrayLiteral(src) {
|
||||
const m = src.match(/protected\s+\$allowedFields\s*=\s*/);
|
||||
if (!m || m.index === undefined) return null;
|
||||
let pos = m.index + m[0].length;
|
||||
while (pos < src.length && /\s/.test(src[pos])) pos++;
|
||||
if (pos >= src.length || src[pos] !== "[") return null;
|
||||
const start = pos;
|
||||
let depth = 0;
|
||||
for (let i = pos; i < src.length; i++) {
|
||||
const c = src[i];
|
||||
if (c === "[") depth++;
|
||||
else if (c === "]") {
|
||||
depth--;
|
||||
if (depth === 0) return src.slice(start, i + 1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseQuotedStrings(arrayLiteral) {
|
||||
const out = [];
|
||||
const re = /'((?:\\'|[^'])*)'/g;
|
||||
let m;
|
||||
while ((m = re.exec(arrayLiteral))) out.push(m[1].replace(/\\'/g, "'"));
|
||||
return out;
|
||||
}
|
||||
|
||||
function renderFillable(items) {
|
||||
const lines = items.map((it) => {
|
||||
const escaped = String(it).replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
||||
return ` '${escaped}',`;
|
||||
});
|
||||
return `[\n${lines.join("\n")}\n ]`;
|
||||
}
|
||||
|
||||
function replaceFillable(lv, inner) {
|
||||
const re = /protected\s+\$fillable\s*=\s*\[[\s\S]*?\];/m;
|
||||
if (!re.test(lv)) return null;
|
||||
return lv.replace(re, `protected $fillable = ${inner};`);
|
||||
}
|
||||
|
||||
function replaceTimestamps(lv, useTs) {
|
||||
const line = useTs ? " public $timestamps = true;" : " public $timestamps = false;";
|
||||
// Normalize any leading whitespace so re-sync does not duplicate lines or pile up indent.
|
||||
if (/^\s*public\s+\$timestamps\s*=\s*(true|false)\s*;/m.test(lv))
|
||||
return lv.replace(/^\s*public\s+\$timestamps\s*=\s*(true|false)\s*;/m, line);
|
||||
return lv.replace(/(class\s+\w+[^\n]*\n\{)/, `$1\n${line}\n`);
|
||||
}
|
||||
|
||||
let updated = 0,
|
||||
skipped = 0;
|
||||
const missing = [];
|
||||
|
||||
const files = await readdir(ciModelsDir).catch(() => []);
|
||||
for (const ciBasename of files) {
|
||||
if (!ciBasename.endsWith("Model.php")) continue;
|
||||
if (skipCiBasenames.has(ciBasename)) {
|
||||
console.error(`Skip CI (legacy): ${ciBasename}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
const laravelBasename = ciFileToLaravel(ciBasename);
|
||||
if (!laravelBasename) continue;
|
||||
if (skipLaravel.has(laravelBasename)) {
|
||||
console.error(`Skip (alias/base): ${laravelBasename}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const lvPath = join(laravelModelsDir, laravelBasename);
|
||||
try {
|
||||
await readFile(lvPath, "utf8");
|
||||
} catch {
|
||||
missing.push(`${laravelBasename} (from ${ciBasename})`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const ciSrc = await readFile(join(ciModelsDir, ciBasename), "utf8");
|
||||
let lvSrc = await readFile(lvPath, "utf8");
|
||||
|
||||
let useTs = true;
|
||||
const tm = ciSrc.match(/protected\s+\$useTimestamps\s*=\s*(true|false)\s*;/);
|
||||
if (tm) useTs = tm[1] === "true";
|
||||
|
||||
const allowedBody = extractAllowedFieldsArrayLiteral(ciSrc);
|
||||
if (!allowedBody) {
|
||||
console.error(`No allowedFields in ${ciBasename}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const fields = parseQuotedStrings(allowedBody);
|
||||
if (!fields.length) {
|
||||
console.error(`Empty allowedFields in ${ciBasename}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!/protected\s+\$fillable\s*=\s*\[/.test(lvSrc)) {
|
||||
console.error(`No $fillable in ${laravelBasename}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const rendered = renderFillable(fields);
|
||||
let next = replaceFillable(lvSrc, rendered);
|
||||
if (next == null) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
next = replaceTimestamps(next, useTs);
|
||||
|
||||
if (next === lvSrc) {
|
||||
console.error(`Unchanged: ${laravelBasename}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
await writeFile(lvPath, next, "utf8");
|
||||
console.log(`Updated ${laravelBasename}`);
|
||||
updated++;
|
||||
}
|
||||
|
||||
console.log(`\nDone. Updated: ${updated}, skipped: ${skipped}`);
|
||||
if (missing.length) {
|
||||
console.error(`Missing (${missing.length}): ${missing.slice(0, 25).join(", ")}${missing.length > 25 ? "…" : ""}`);
|
||||
process.exitCode = 2;
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Sync Laravel models from CodeIgniter 4 *Model.php siblings (mass-assignment parity).
|
||||
*
|
||||
* Updates only:
|
||||
* - protected $fillable ← CI protected $allowedFields (order preserved)
|
||||
* - public $timestamps ← CI protected $useTimestamps
|
||||
*
|
||||
* Does NOT overwrite $table / $primaryKey (schemas may diverge: e.g. flag vs current_flag).
|
||||
*
|
||||
* Skips Laravel: Teacher (extends User), Communication, EventCharge, ClassModel, Calendar aliases.
|
||||
*
|
||||
* Usage (from app_laravel directory):
|
||||
* php tools/sync_fillable_from_codeigniter.php
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
const NL = "\n";
|
||||
|
||||
$laravelRoot = dirname(__DIR__);
|
||||
$workspaceRoot = dirname($laravelRoot);
|
||||
$ciModelsDir = $workspaceRoot.DIRECTORY_SEPARATOR.'app_codeigniter'.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'Models';
|
||||
$laravelModelsDir = $laravelRoot.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'Models';
|
||||
|
||||
if (! is_dir($ciModelsDir)) {
|
||||
fwrite(STDERR, "CI models dir not found: {$ciModelsDir}".NL);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** CI Model basename => Laravel model basename */
|
||||
$manualCiToLaravel = [
|
||||
'FlagModel.php' => 'CurrentFlag.php',
|
||||
];
|
||||
|
||||
/** Laravel files skipped (aliases / inheritance) */
|
||||
$skipLaravelBasenames = [
|
||||
'Teacher.php',
|
||||
'Communication.php',
|
||||
'EventCharge.php',
|
||||
'ClassModel.php',
|
||||
'Calendar.php',
|
||||
];
|
||||
|
||||
function ciFileToLaravelFile(string $ciBasename, array $manual): ?string
|
||||
{
|
||||
if (isset($manual[$ciBasename])) {
|
||||
return $manual[$ciBasename];
|
||||
}
|
||||
if (! preg_match('/^(.+)Model\.php$/', $ciBasename, $m)) {
|
||||
return null;
|
||||
}
|
||||
$base = $m[1];
|
||||
if ($base === 'Parent' || $base === 'Class') {
|
||||
return $base.'Model.php';
|
||||
}
|
||||
|
||||
return $base.'.php';
|
||||
}
|
||||
|
||||
function extractFirstBracketArray(string $src, string $needle): ?string
|
||||
{
|
||||
$pos = strpos($src, $needle);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$pos += strlen($needle);
|
||||
$len = strlen($src);
|
||||
while ($pos < $len && ctype_space($src[$pos])) {
|
||||
$pos++;
|
||||
}
|
||||
if ($pos >= $len || $src[$pos] !== '[') {
|
||||
return null;
|
||||
}
|
||||
$start = $pos;
|
||||
$depth = 0;
|
||||
for ($i = $pos; $i < $len; $i++) {
|
||||
$c = $src[$i];
|
||||
if ($c === '[') {
|
||||
$depth++;
|
||||
} elseif ($c === ']') {
|
||||
$depth--;
|
||||
if ($depth === 0) {
|
||||
return substr($src, $start, $i - $start + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
function parseQuotedStringsFromArrayLiteral(string $arrayLiteral): array
|
||||
{
|
||||
$out = [];
|
||||
if (! preg_match_all("/'((?:\\\\'|[^'])*)'/", $arrayLiteral, $m)) {
|
||||
return $out;
|
||||
}
|
||||
foreach ($m[1] as $raw) {
|
||||
$out[] = str_replace("\\'", "'", $raw);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/** Render inner array only: [\n 'a',\n ] */
|
||||
function renderFillableArray(array $items): string
|
||||
{
|
||||
$lines = [];
|
||||
foreach ($items as $item) {
|
||||
$escaped = addcslashes($item, "\\'");
|
||||
$lines[] = " '".$escaped."',";
|
||||
}
|
||||
|
||||
return "[\n".implode("\n", $lines)."\n ]";
|
||||
}
|
||||
|
||||
function replaceFillableBlock(string $laravel, string $newArrayLiteral): string
|
||||
{
|
||||
$re = '/protected\s+\$fillable\s*=\s*\[[\s\S]*?\];/m';
|
||||
if (! preg_match($re, $laravel)) {
|
||||
return $laravel;
|
||||
}
|
||||
|
||||
return preg_replace($re, 'protected $fillable = '.$newArrayLiteral.';', $laravel, 1);
|
||||
}
|
||||
|
||||
function replaceTimestampsLine(string $laravel, bool $useTimestamps): string
|
||||
{
|
||||
$line = $useTimestamps
|
||||
? ' public $timestamps = true;'
|
||||
: ' public $timestamps = false;';
|
||||
|
||||
if (preg_match('/public\s+\$timestamps\s*=\s*(true|false)\s*;/', $laravel)) {
|
||||
return preg_replace(
|
||||
'/public\s+\$timestamps\s*=\s*(true|false)\s*;/',
|
||||
$line,
|
||||
$laravel,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
// Insert after class opening brace line (first line after "class X extends Y")
|
||||
return preg_replace(
|
||||
'/(class\s+\w+[^\n]*\n\{[\t ]*\n)/',
|
||||
'$1'.$line.NL.NL,
|
||||
$laravel,
|
||||
1
|
||||
) ?: preg_replace('/(class\s+\w+[^\n]*\n\{)/', '$1'.NL.$line, $laravel, 1);
|
||||
}
|
||||
|
||||
$updated = 0;
|
||||
$skipped = 0;
|
||||
$missing = [];
|
||||
|
||||
foreach (glob($ciModelsDir.DIRECTORY_SEPARATOR.'*Model.php') ?: [] as $ciPath) {
|
||||
$ciBasename = basename($ciPath);
|
||||
$laravelBasename = ciFileToLaravelFile($ciBasename, $manualCiToLaravel);
|
||||
if ($laravelBasename === null) {
|
||||
continue;
|
||||
}
|
||||
if (in_array($laravelBasename, $skipLaravelBasenames, true)) {
|
||||
fwrite(STDERR, "Skip (alias/base): {$laravelBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$lvPath = $laravelModelsDir.DIRECTORY_SEPARATOR.$laravelBasename;
|
||||
if (! is_file($lvPath)) {
|
||||
$missing[] = $laravelBasename.' (from '.$ciBasename.')';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$ciSrc = (string) file_get_contents($ciPath);
|
||||
$lvSrc = (string) file_get_contents($lvPath);
|
||||
|
||||
$useTs = true;
|
||||
if (preg_match('/protected\s+\$useTimestamps\s*=\s*(true|false)\s*;/', $ciSrc, $tm)) {
|
||||
$useTs = $tm[1] === 'true';
|
||||
}
|
||||
|
||||
$allowedBody = extractFirstBracketArray($ciSrc, 'protected $allowedFields = ');
|
||||
if ($allowedBody === null) {
|
||||
fwrite(STDERR, "No allowedFields in {$ciBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields = parseQuotedStringsFromArrayLiteral($allowedBody);
|
||||
if ($fields === []) {
|
||||
fwrite(STDERR, "Empty allowedFields in {$ciBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! preg_match('/protected\s+\$fillable\s*=\s*\[/', $lvSrc)) {
|
||||
fwrite(STDERR, "No \$fillable array in {$laravelBasename} — add manually".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$rendered = renderFillableArray($fields);
|
||||
$newLv = replaceFillableBlock($lvSrc, $rendered);
|
||||
$newLv = replaceTimestampsLine($newLv, $useTs);
|
||||
|
||||
if ($newLv === $lvSrc) {
|
||||
fwrite(STDERR, "Unchanged: {$laravelBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
file_put_contents($lvPath, $newLv);
|
||||
fwrite(STDOUT, "Updated {$laravelBasename}".NL);
|
||||
$updated++;
|
||||
}
|
||||
|
||||
fwrite(STDOUT, NL.'Done. Updated: '.$updated.', skipped: '.$skipped.NL);
|
||||
if ($missing !== []) {
|
||||
fwrite(STDERR, 'Missing Laravel files ('.count($missing).'): '.implode(', ', array_slice($missing, 0, 20)).(count($missing) > 20 ? '…' : '').NL);
|
||||
|
||||
exit(2);
|
||||
}
|
||||
Reference in New Issue
Block a user