db->tableExists($table)) { return; } } $students = $this->db->query( "SELECT s.id AS student_id, s.parent_id, u.firstname, u.lastname FROM students s JOIN users u ON u.id = s.parent_id LEFT JOIN family_students fs ON fs.student_id = s.id WHERE fs.id IS NULL AND s.parent_id IS NOT NULL AND s.parent_id > 0 ORDER BY s.id" )->getResultArray(); foreach ($students as $student) { $studentId = (int) ($student['student_id'] ?? 0); $parentId = (int) ($student['parent_id'] ?? 0); if ($studentId <= 0 || $parentId <= 0) { continue; } $family = $this->db->query( "SELECT f.id FROM families f LEFT JOIN family_guardians fg ON fg.family_id = f.id AND fg.user_id = ? WHERE f.family_code = ? OR fg.user_id = ? ORDER BY (f.family_code = ?) DESC, fg.is_primary DESC, f.id ASC LIMIT 1", [$parentId, 'FAM-' . $parentId, $parentId, 'FAM-' . $parentId] )->getRowArray(); if (empty($family['id'])) { $parentName = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')); $this->db->table('families')->insert([ 'family_code' => 'FAM-' . $parentId, 'household_name' => $parentName !== '' ? 'Family of ' . $parentName : 'Family of User ' . $parentId, 'is_active' => 1, ]); $family['id'] = (int) $this->db->insertID(); } $familyId = (int) ($family['id'] ?? 0); if ($familyId <= 0) { throw new \RuntimeException('Could not create a family for parent ID ' . $parentId . '.'); } $this->db->query( 'INSERT IGNORE INTO family_guardians (family_id, user_id, relation, is_primary, receive_emails, receive_sms) VALUES (?, ?, ?, 1, 1, 0)', [$familyId, $parentId, 'primary'] ); $this->db->query( 'INSERT IGNORE INTO family_students (family_id, student_id, is_primary_home) VALUES (?, ?, 1)', [$familyId, $studentId] ); } } public function down(): void { // This repair is intentionally irreversible for the same reason as the // preceding family-membership backfill. } }