This commit is contained in:
@@ -8,6 +8,10 @@ class AddEventCategoryToEvents extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('events')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('events');
|
||||
|
||||
if (!in_array('event_category', $fields, true)) {
|
||||
@@ -25,6 +29,10 @@ class AddEventCategoryToEvents extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('events')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('events');
|
||||
|
||||
if (in_array('event_category', $fields, true)) {
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddBatchNumberToReimbursements extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('reimbursements') || $this->db->fieldExists('batch_number', 'reimbursements')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'batch_number' => [
|
||||
'type' => 'INT',
|
||||
@@ -24,7 +28,10 @@ class AddBatchNumberToReimbursements extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('reimbursements') || ! $this->db->fieldExists('batch_number', 'reimbursements')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->dropColumn('reimbursements', 'batch_number');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -8,6 +8,10 @@ class AddYearlyBatchNumberToReimbursementBatches extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('reimbursement_batches') || $this->db->fieldExists('yearly_batch_number', 'reimbursement_batches')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'yearly_batch_number' => [
|
||||
'type' => 'INT',
|
||||
@@ -26,6 +30,10 @@ class AddYearlyBatchNumberToReimbursementBatches extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('reimbursement_batches') || ! $this->db->fieldExists('yearly_batch_number', 'reimbursement_batches')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->dropColumn('reimbursement_batches', 'yearly_batch_number');
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ class CreateStaffAttendance extends Migration
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['user_id','date','semester','school_year']);
|
||||
$this->forge->addForeignKey('user_id','users','id','CASCADE','CASCADE');
|
||||
if ($this->db->tableExists('users')) {
|
||||
$this->forge->addForeignKey('user_id','users','id','CASCADE','CASCADE');
|
||||
}
|
||||
$this->forge->createTable('staff_attendance', true);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ class CreateFamiliesTables extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['family_id', 'student_id']);
|
||||
$this->forge->addForeignKey('family_id', 'families', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('student_id', 'students', 'id', 'CASCADE', 'CASCADE');
|
||||
if ($this->db->tableExists('students')) {
|
||||
$this->forge->addForeignKey('student_id', 'students', 'id', 'CASCADE', 'CASCADE');
|
||||
}
|
||||
$this->forge->createTable('family_students', true);
|
||||
|
||||
// family_guardians
|
||||
@@ -62,7 +64,9 @@ class CreateFamiliesTables extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['family_id', 'user_id']);
|
||||
$this->forge->addForeignKey('family_id', 'families', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('user_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
if ($this->db->tableExists('users')) {
|
||||
$this->forge->addForeignKey('user_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
}
|
||||
$this->forge->createTable('family_guardians', true);
|
||||
|
||||
// family_comm_prefs
|
||||
@@ -90,4 +94,3 @@ class CreateFamiliesTables extends Migration
|
||||
$this->forge->dropTable('families', true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@ class AddNoSchoolToCalendarEvents extends Migration
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (! $db->tableExists('calendar_events')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cols = [];
|
||||
try {
|
||||
$cols = $db->getFieldNames('calendar_events');
|
||||
@@ -31,6 +35,10 @@ class AddNoSchoolToCalendarEvents extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('calendar_events')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->forge->dropColumn('calendar_events', 'no_school');
|
||||
} catch (\Throwable $e) {
|
||||
@@ -38,4 +46,3 @@ class AddNoSchoolToCalendarEvents extends Migration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,8 +85,12 @@ class CreateParentAttendanceReports extends Migration
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['report_date']);
|
||||
$this->forge->addKey(['student_id', 'report_date']);
|
||||
$this->forge->addForeignKey('parent_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('student_id', 'students', 'id', 'CASCADE', 'CASCADE');
|
||||
if ($this->db->tableExists('users')) {
|
||||
$this->forge->addForeignKey('parent_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
}
|
||||
if ($this->db->tableExists('students')) {
|
||||
$this->forge->addForeignKey('student_id', 'students', 'id', 'CASCADE', 'CASCADE');
|
||||
}
|
||||
$this->forge->createTable('parent_attendance_reports', true);
|
||||
}
|
||||
|
||||
@@ -97,4 +101,3 @@ class CreateParentAttendanceReports extends Migration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ class AddDonationCategoryToExpenses extends Migration
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('expenses')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->modifyColumn('expenses', [
|
||||
'category' => [
|
||||
'type' => "ENUM('Expense','Purchase','Reimbursement','Donation')",
|
||||
@@ -24,6 +28,10 @@ class AddDonationCategoryToExpenses extends Migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('expenses')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert any donation rows to Expense to keep rollback safe.
|
||||
$this->db->table('expenses')
|
||||
->where('category', 'Donation')
|
||||
|
||||
@@ -61,9 +61,13 @@ class CreatePrintRequests extends Migration
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addForeignKey('teacher_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('admin_id', 'users', 'id', 'CASCADE', 'SET NULL');
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
if ($this->db->tableExists('users')) {
|
||||
$this->forge->addForeignKey('teacher_id', 'users', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->addForeignKey('admin_id', 'users', 'id', 'CASCADE', 'SET NULL');
|
||||
}
|
||||
if ($this->db->tableExists('classes')) {
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
}
|
||||
$this->forge->createTable('print_requests');
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,16 @@ class FixPrintRequestsForeignKey extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop the old foreign key if it exists
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('class_sections')) {
|
||||
return;
|
||||
@@ -24,8 +32,20 @@ class FixPrintRequestsForeignKey extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop the new foreign key
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('classes')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-add the old foreign key
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
@@ -8,16 +8,28 @@ class RevertPrintRequestsForeignKey extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop the old foreign key if it exists
|
||||
$db = \Config\Database::connect();
|
||||
$keys = $db->getForeignKeyData('print_requests');
|
||||
foreach ($keys as $key) {
|
||||
if ($key->constraint_name === 'print_requests_class_id_foreign') {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('classes')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the new foreign key
|
||||
$this->forge->addForeignKey('class_id', 'classes', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
@@ -27,8 +39,20 @@ class RevertPrintRequestsForeignKey extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop the new foreign key
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('class_sections')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-add the old foreign key
|
||||
$this->forge->addForeignKey('class_id', 'class_sections', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
@@ -8,12 +8,24 @@ class DropPrintRequestsForeignKey extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop the old foreign key if it exists
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests') || ! $this->db->tableExists('class_sections')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-add the old foreign key
|
||||
$this->forge->addForeignKey('class_id', 'class_sections', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
|
||||
+22
-2
@@ -8,21 +8,41 @@ class FixPrintRequestsForeignKeyOnceAndForAll extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$keys = $db->getForeignKeyData('print_requests');
|
||||
foreach ($keys as $key) {
|
||||
if ($key->constraint_name === 'print_requests_class_id_foreign') {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('classSection')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addForeignKey('class_id', 'classSection', 'id', 'CASCADE', 'CASCADE');
|
||||
$this->forge->processIndexes('print_requests');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ class FixPrintRequestsForeignKeyAgain extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('print_requests') || ! $this->db->tableExists('classSection')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$keys = $db->getForeignKeyData('print_requests');
|
||||
foreach ($keys as $key) {
|
||||
@@ -22,6 +26,14 @@ class FixPrintRequestsForeignKeyAgain extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
if (! $this->db->tableExists('print_requests')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->forge->dropForeignKey('print_requests', 'print_requests_class_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Already absent.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ class AddEventTypeToCalendarEvents extends Migration
|
||||
public function up()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (! $db->tableExists('calendar_events')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$db->fieldExists('event_type', 'calendar_events')) {
|
||||
$this->forge->addColumn('calendar_events', [
|
||||
@@ -26,6 +29,10 @@ class AddEventTypeToCalendarEvents extends Migration
|
||||
public function down()
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
if (! $db->tableExists('calendar_events')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($db->fieldExists('event_type', 'calendar_events')) {
|
||||
$this->forge->dropColumn('calendar_events', 'event_type');
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddEventPaidFlagToCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'event_paid' => [
|
||||
'type' => 'TINYINT',
|
||||
@@ -17,11 +21,15 @@ class AddEventPaidFlagToCharges extends Migration
|
||||
],
|
||||
];
|
||||
|
||||
$this->forge->addColumn('event_charges', $fields);
|
||||
if (! $this->db->fieldExists('event_paid', 'event_charges')) {
|
||||
$this->forge->addColumn('event_charges', $fields);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('event_charges', 'event_paid');
|
||||
if ($this->db->tableExists('event_charges') && $this->db->fieldExists('event_paid', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'event_paid');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddClassSectionToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
@@ -25,7 +29,7 @@ class AddClassSectionToEventCharges extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->fieldExists('class_section_id', 'event_charges')) {
|
||||
if ($this->db->tableExists('event_charges') && $this->db->fieldExists('class_section_id', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'class_section_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddEventPaymentRefToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'event_payment_id' => [
|
||||
'type' => 'INT',
|
||||
@@ -25,7 +29,7 @@ class AddEventPaymentRefToEventCharges extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->fieldExists('event_payment_id', 'event_charges')) {
|
||||
if ($this->db->tableExists('event_charges') && $this->db->fieldExists('event_payment_id', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'event_payment_id');
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -8,6 +8,10 @@ class AddExternalParticipantFieldsToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'external_firstname' => [
|
||||
'type' => 'VARCHAR',
|
||||
@@ -34,6 +38,10 @@ class AddExternalParticipantFieldsToEventCharges extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (['external_firstname', 'external_lastname', 'external_note'] as $field) {
|
||||
if ($this->db->fieldExists($field, 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', $field);
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddExternalParentInfoToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'external_parent_firstname' => [
|
||||
'type' => 'VARCHAR',
|
||||
@@ -34,6 +38,10 @@ class AddExternalParentInfoToEventCharges extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (['external_parent_firstname', 'external_parent_lastname', 'external_parent_phone'] as $field) {
|
||||
if ($this->db->fieldExists($field, 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', $field);
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddExternalParentEmailToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'external_parent_email' => [
|
||||
'type' => 'VARCHAR',
|
||||
@@ -24,9 +28,8 @@ class AddExternalParentEmailToEventCharges extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->fieldExists('external_parent_email', 'event_charges')) {
|
||||
if ($this->db->tableExists('event_charges') && $this->db->fieldExists('external_parent_email', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'external_parent_email');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ class AddWaiverSignedToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('event_charges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'waiver_signed' => [
|
||||
'type' => 'TINYINT',
|
||||
@@ -24,7 +28,7 @@ class AddWaiverSignedToEventCharges extends Migration
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->fieldExists('waiver_signed', 'event_charges')) {
|
||||
if ($this->db->tableExists('event_charges') && $this->db->fieldExists('waiver_signed', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'waiver_signed');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddDescriptionToInvoices extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->db->tableExists('invoices') || $this->db->fieldExists('description', 'invoices')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addColumn('invoices', [
|
||||
'description' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
'after' => 'status',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if ($this->db->tableExists('invoices') && $this->db->fieldExists('description', 'invoices')) {
|
||||
$this->forge->dropColumn('invoices', 'description');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
use RuntimeException;
|
||||
|
||||
final class AlignSchemaToScoolViewDump extends Migration
|
||||
{
|
||||
/**
|
||||
* Columns present in school_prod.sql.zip but absent from scool_view.sql.zip.
|
||||
*
|
||||
* This migration intentionally makes the live database match the scool_view
|
||||
* dump captured on 2026-07-17.
|
||||
*/
|
||||
private array $columnsToDrop = [
|
||||
'classSection' => ['semester'],
|
||||
'contactus' => ['semester'],
|
||||
'discount_vouchers' => ['semester'],
|
||||
'emergency_contacts' => ['semester', 'school_year'],
|
||||
'ip_attempts' => ['semester'],
|
||||
'login_activity' => ['semester'],
|
||||
'notification_recipients' => ['semester'],
|
||||
'notifications' => ['semester'],
|
||||
'parents' => ['semester', 'school_year'],
|
||||
'payment_error' => ['semester'],
|
||||
'payment_transactions' => ['semester'],
|
||||
'payments' => ['semester'],
|
||||
'paypal_transactions' => ['semester'],
|
||||
'preferences' => ['school_year'],
|
||||
'refunds' => ['semester'],
|
||||
'reimbursement_batch_items' => ['semester'],
|
||||
'reimbursement_batches' => ['semester'],
|
||||
'reimbursements' => ['semester'],
|
||||
'students' => ['semester', 'school_year'],
|
||||
'support_requests' => ['semester'],
|
||||
'user_notifications' => ['semester'],
|
||||
'users' => ['semester', 'school_year'],
|
||||
'whatsapp_group_links' => ['semester'],
|
||||
'whatsapp_group_memberships' => ['semester'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Tables that should own a required school_year value after aligning the schema.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
private array $schoolYearTables = [
|
||||
'admin_notification_subjects',
|
||||
'attendance_comment_template',
|
||||
'class_progress_attachments',
|
||||
'competition_class_winners',
|
||||
'competition_scores',
|
||||
'competition_winners',
|
||||
'inventory_categories',
|
||||
'paypal_payments',
|
||||
'placement_scores',
|
||||
'promotion_queue',
|
||||
'qcmquestions',
|
||||
'school_year_closing_batches',
|
||||
'school_year_closing_items',
|
||||
'school_year_transition_logs',
|
||||
'staff',
|
||||
'whatsapp_group_links',
|
||||
'whatsapp_invites_log',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
if ($this->db->DBDriver !== 'MySQLi') {
|
||||
throw new RuntimeException('This migration requires MySQL/MariaDB through the MySQLi driver.');
|
||||
}
|
||||
|
||||
$this->dropIndexIfExists('competition_winners', 'competition_id_class_section_id_rank');
|
||||
$this->dropIndexIfExists('refunds', 'idx_refunds_parent_year_semester_status');
|
||||
$this->dropIndexIfExists('teacher_class', 'idx_sy_teacher_class_school_year_223511c0');
|
||||
$this->dropIndexIfExists('whatsapp_group_links', 'uq_section_term');
|
||||
$this->dropIndexIfExists('whatsapp_group_memberships', 'uniq_whatsapp_membership');
|
||||
$this->dropIndexIfExists('whatsapp_group_memberships', 'class_section_id_school_year_semester');
|
||||
|
||||
foreach ($this->columnsToDrop as $table => $columns) {
|
||||
foreach ($columns as $column) {
|
||||
$this->dropColumnIfExists($table, $column);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->resetDataCache();
|
||||
|
||||
foreach ($this->schoolYearTables as $table) {
|
||||
$this->ensureRequiredSchoolYearColumn($table);
|
||||
}
|
||||
|
||||
$this->db->resetDataCache();
|
||||
|
||||
$this->ensureIndex(
|
||||
'refunds',
|
||||
'idx_refunds_parent_year_semester_status',
|
||||
['parent_id', 'school_year', 'status']
|
||||
);
|
||||
|
||||
$this->ensureIndex(
|
||||
'teacher_class',
|
||||
'unique_teacher_assignment',
|
||||
['teacher_id', 'class_section_id', 'school_year'],
|
||||
true
|
||||
);
|
||||
|
||||
$this->ensureIndex(
|
||||
'whatsapp_group_links',
|
||||
'uq_section_term',
|
||||
['class_section_id'],
|
||||
true
|
||||
);
|
||||
|
||||
$this->ensureIndex(
|
||||
'whatsapp_group_memberships',
|
||||
'uniq_whatsapp_membership',
|
||||
['class_section_id', 'school_year', 'subject_type', 'subject_id'],
|
||||
true
|
||||
);
|
||||
|
||||
$this->ensureIndex(
|
||||
'whatsapp_group_memberships',
|
||||
'class_section_id_school_year_semester',
|
||||
['class_section_id', 'school_year']
|
||||
);
|
||||
|
||||
if ($this->db->tableExists('whatsapp_group_links')) {
|
||||
$this->db->query(
|
||||
'ALTER TABLE `whatsapp_group_links` ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
throw new RuntimeException(
|
||||
'This migration is intentionally irreversible because matching scool_view drops columns and their data.'
|
||||
);
|
||||
}
|
||||
|
||||
private function ensureRequiredSchoolYearColumn(string $table): void
|
||||
{
|
||||
if (! $this->db->tableExists($table)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->db->fieldExists('school_year', $table)) {
|
||||
$this->forge->addColumn($table, [
|
||||
'school_year' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 9,
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$year = $this->currentSchoolYear();
|
||||
$this->db->query(
|
||||
sprintf(
|
||||
'UPDATE %s SET `school_year` = ? WHERE `school_year` IS NULL OR TRIM(`school_year`) = \'\'',
|
||||
$this->quoteIdentifier($table)
|
||||
),
|
||||
[$year]
|
||||
);
|
||||
|
||||
$this->db->query(sprintf(
|
||||
'ALTER TABLE %s MODIFY `school_year` VARCHAR(9) NOT NULL',
|
||||
$this->quoteIdentifier($table)
|
||||
));
|
||||
}
|
||||
|
||||
private function currentSchoolYear(): string
|
||||
{
|
||||
if ($this->db->tableExists('configuration')) {
|
||||
$row = $this->db->table('configuration')
|
||||
->select('config_value')
|
||||
->whereIn('config_key', ['school_year', 'current_school_year'])
|
||||
->where('config_value IS NOT NULL', null, false)
|
||||
->where('TRIM(config_value) <>', '')
|
||||
->orderBy("FIELD(config_key, 'school_year', 'current_school_year')", '', false)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
if (isset($row['config_value']) && preg_match('/^\d{4}-\d{4}$/', (string) $row['config_value'])) {
|
||||
return (string) $row['config_value'];
|
||||
}
|
||||
}
|
||||
|
||||
$year = (int) date('Y');
|
||||
|
||||
return $year . '-' . ($year + 1);
|
||||
}
|
||||
|
||||
private function dropColumnIfExists(string $table, string $column): void
|
||||
{
|
||||
if (! $this->db->tableExists($table) || ! $this->db->fieldExists($column, $table)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->dropForeignKeysContainingColumn($table, $column);
|
||||
$this->dropIndexesContainingColumn($table, $column);
|
||||
$this->dropChecksContainingColumn($table, $column);
|
||||
|
||||
$this->forge->dropColumn($table, $column);
|
||||
}
|
||||
|
||||
private function ensureIndex(string $table, string $index, array $columns, bool $unique = false): void
|
||||
{
|
||||
if (! $this->db->tableExists($table) || ! $this->hasColumns($table, $columns)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->indexExists($table, $index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$keyword = $unique ? 'UNIQUE INDEX' : 'INDEX';
|
||||
$columnList = implode(', ', array_map([$this, 'quoteIdentifier'], $columns));
|
||||
|
||||
$this->db->query(sprintf(
|
||||
'ALTER TABLE %s ADD %s %s (%s)',
|
||||
$this->quoteIdentifier($table),
|
||||
$keyword,
|
||||
$this->quoteIdentifier($index),
|
||||
$columnList
|
||||
));
|
||||
}
|
||||
|
||||
private function dropIndexIfExists(string $table, string $index): void
|
||||
{
|
||||
if (! $this->db->tableExists($table) || ! $this->indexExists($table, $index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->query(sprintf(
|
||||
'ALTER TABLE %s DROP INDEX %s',
|
||||
$this->quoteIdentifier($table),
|
||||
$this->quoteIdentifier($index)
|
||||
));
|
||||
}
|
||||
|
||||
private function dropIndexesContainingColumn(string $table, string $column): void
|
||||
{
|
||||
$indexes = $this->db->query(
|
||||
'SELECT DISTINCT INDEX_NAME
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = ?
|
||||
AND COLUMN_NAME = ?
|
||||
AND INDEX_NAME <> \'PRIMARY\'',
|
||||
[$table, $column]
|
||||
)->getResult();
|
||||
|
||||
foreach ($indexes as $index) {
|
||||
$this->dropIndexIfExists($table, $index->INDEX_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private function dropForeignKeysContainingColumn(string $table, string $column): void
|
||||
{
|
||||
$constraints = $this->db->query(
|
||||
'SELECT DISTINCT CONSTRAINT_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = ?
|
||||
AND COLUMN_NAME = ?
|
||||
AND REFERENCED_TABLE_NAME IS NOT NULL',
|
||||
[$table, $column]
|
||||
)->getResult();
|
||||
|
||||
foreach ($constraints as $constraint) {
|
||||
$this->db->query(sprintf(
|
||||
'ALTER TABLE %s DROP FOREIGN KEY %s',
|
||||
$this->quoteIdentifier($table),
|
||||
$this->quoteIdentifier($constraint->CONSTRAINT_NAME)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function dropChecksContainingColumn(string $table, string $column): void
|
||||
{
|
||||
$checks = $this->db->query(
|
||||
'SELECT tc.CONSTRAINT_NAME
|
||||
FROM information_schema.TABLE_CONSTRAINTS tc
|
||||
INNER JOIN information_schema.CHECK_CONSTRAINTS cc
|
||||
ON cc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
|
||||
AND cc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
|
||||
WHERE tc.CONSTRAINT_SCHEMA = DATABASE()
|
||||
AND tc.TABLE_NAME = ?
|
||||
AND tc.CONSTRAINT_TYPE = \'CHECK\'
|
||||
AND cc.CHECK_CLAUSE LIKE ?',
|
||||
[$table, '%' . $column . '%']
|
||||
)->getResult();
|
||||
|
||||
foreach ($checks as $check) {
|
||||
$this->db->query(sprintf(
|
||||
'ALTER TABLE %s DROP CHECK %s',
|
||||
$this->quoteIdentifier($table),
|
||||
$this->quoteIdentifier($check->CONSTRAINT_NAME)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function indexExists(string $table, string $index): bool
|
||||
{
|
||||
$row = $this->db->query(
|
||||
'SELECT COUNT(*) AS aggregate
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = ?
|
||||
AND INDEX_NAME = ?',
|
||||
[$table, $index]
|
||||
)->getRow();
|
||||
|
||||
return (int) ($row->aggregate ?? 0) > 0;
|
||||
}
|
||||
|
||||
private function hasColumns(string $table, array $columns): bool
|
||||
{
|
||||
foreach ($columns as $column) {
|
||||
if (! $this->db->fieldExists($column, $table)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function quoteIdentifier(string $identifier): string
|
||||
{
|
||||
return '`' . str_replace('`', '``', $identifier) . '`';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user