Files
alrahma_sunday_school/app/Services/AdministratorDirectoryService.php
T
root 889c037660
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 48s
Tests / PHPUnit (push) Failing after 1m22s
fix is_new issue with enrollment fixes
2026-08-20 19:57:25 -04:00

229 lines
9.0 KiB
PHP

<?php
namespace App\Services;
use App\Models\InvoiceModel;
use App\Models\StudentClassModel;
use App\Models\StudentModel;
use App\Models\UserModel;
use App\Models\UserRoleModel;
use App\Support\Enrollment\EnrollmentEligibility;
class AdministratorDirectoryService
{
protected $db;
protected $studentClassModel;
protected $userModel;
protected $userRoleModel;
protected $invoiceModel;
protected $studentModel;
public function __construct(
\CodeIgniter\Database\BaseConnection $db,
StudentClassModel $studentClassModel,
UserModel $userModel,
UserRoleModel $userRoleModel,
InvoiceModel $invoiceModel,
StudentModel $studentModel
) {
$this->db = $db;
$this->studentClassModel = $studentClassModel;
$this->userModel = $userModel;
$this->userRoleModel = $userRoleModel;
$this->invoiceModel = $invoiceModel;
$this->studentModel = $studentModel;
}
public function studentProfiles(string $selectedYear): array
{
$db = db_connect();
$isPg = ($db->getPlatform() === 'Postgre'); // 'MySQLi', 'Postgre', 'SQLSRV', ...
// In MySQL, avoid truncation of long lists
if (!$isPg) {
$db->query('SET SESSION group_concat_max_len = 8192');
}
$b = $db->table('students');
if ($isPg) {
// Postgres: use subqueries for aggregates to avoid GROUP BY on students.*
$students = $b->select([
'students.*',
'users.firstname AS parent_firstname',
'users.lastname AS parent_lastname',
'users.email AS parent_email',
'users.cellphone AS parent_phone',
// Pick one emergency contact (first by id)
"(SELECT ec.emergency_contact_name FROM emergency_contacts ec
WHERE ec.parent_id = students.parent_id
ORDER BY ec.id ASC LIMIT 1) AS emergency_name",
"(SELECT ec.relation FROM emergency_contacts ec
WHERE ec.parent_id = students.parent_id
ORDER BY ec.id ASC LIMIT 1) AS emergency_relationship",
"(SELECT ec.cellphone FROM emergency_contacts ec
WHERE ec.parent_id = students.parent_id
ORDER BY ec.id ASC LIMIT 1) AS emergency_phone",
"(SELECT ec.email FROM emergency_contacts ec
WHERE ec.parent_id = students.parent_id
ORDER BY ec.id ASC LIMIT 1) AS emergency_email",
// Aggregated lists
"(SELECT STRING_AGG(DISTINCT sa.allergy, ', ' ORDER BY sa.allergy)
FROM student_allergies sa WHERE sa.student_id = students.id) AS allergies",
"(SELECT STRING_AGG(DISTINCT smc.condition_name, ', ' ORDER BY smc.condition_name)
FROM student_medical_conditions smc WHERE smc.student_id = students.id) AS medical_conditions",
])
->join('users', 'users.id = students.parent_id', 'left')
->orderBy('students.lastname', 'ASC')
->orderBy('students.firstname', 'ASC')
->get()
->getResultArray();
} else {
// MySQL: GROUP_CONCAT + MIN() for emergency_* to satisfy ONLY_FULL_GROUP_BY
$students = $b->select([
'students.*',
'users.firstname AS parent_firstname',
'users.lastname AS parent_lastname',
'users.email AS parent_email',
'users.cellphone AS parent_phone',
'MIN(emergency_contacts.emergency_contact_name) AS emergency_name',
'MIN(emergency_contacts.relation) AS emergency_relationship',
'MIN(emergency_contacts.cellphone) AS emergency_phone',
'MIN(emergency_contacts.email) AS emergency_email',
"GROUP_CONCAT(DISTINCT student_allergies.allergy
ORDER BY student_allergies.allergy SEPARATOR ', ') AS allergies",
"GROUP_CONCAT(DISTINCT student_medical_conditions.condition_name
ORDER BY student_medical_conditions.condition_name SEPARATOR ', ') AS medical_conditions",
])
->join('users', 'users.id = students.parent_id', 'left')
->join('emergency_contacts', 'emergency_contacts.parent_id = students.parent_id', 'left')
->join('student_allergies', 'student_allergies.student_id = students.id', 'left')
->join('student_medical_conditions', 'student_medical_conditions.student_id = students.id', 'left')
->groupBy('students.id')
->orderBy('students.lastname', 'ASC')
->orderBy('students.firstname', 'ASC')
->get()
->getResultArray();
}
if ($selectedYear !== '') {
service('studentYearStatus')->attachToStudents($students, $selectedYear);
}
$enrollmentStatusByStudentId = [];
$studentIds = array_values(array_unique(array_filter(array_map(
static fn (array $row): int => (int) ($row['id'] ?? 0),
$students
))));
if ($selectedYear !== '' && !empty($studentIds)) {
$enrollmentRows = $db->table('enrollments')
->select('student_id, enrollment_status')
->whereIn('student_id', $studentIds)
->where('school_year', $selectedYear)
->orderBy('student_id', 'ASC')
->orderBy('updated_at', 'DESC')
->orderBy('enrollment_date', 'DESC')
->orderBy('id', 'DESC')
->get()
->getResultArray();
foreach ($enrollmentRows as $enrollmentRow) {
$studentId = (int) ($enrollmentRow['student_id'] ?? 0);
if ($studentId > 0 && !isset($enrollmentStatusByStudentId[$studentId])) {
$enrollmentStatusByStudentId[$studentId] = (string) ($enrollmentRow['enrollment_status'] ?? '');
}
}
}
// === Inject current-year class_section_name from student_class and replace grade ===
foreach ($students as $i => $row) {
$sid = (int) ($row['id'] ?? 0);
if ($sid > 0) {
$classSectionName = (string) ($this->studentClassModel->getClassSectionNameByStudentId($sid, $selectedYear) ?? '');
$students[$i]['class_section_name'] = $classSectionName;
$students[$i]['enrollment_status'] = $enrollmentStatusByStudentId[$sid] ?? '';
} else {
// Keep keys consistent even if id missing
$students[$i]['class_section_name'] = '';
$students[$i]['enrollment_status'] = '';
}
$studentYear = trim((string) ($row['school_year'] ?? ''));
$students[$i]['age'] = EnrollmentEligibility::ageOnSeptemberFirst(
$row['dob'] ?? null,
$studentYear !== '' ? $studentYear : $selectedYear
);
}
// === end injection ===
return [
'students' => $students,
'gradeOptions' => ['K', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'Youth'],
'genderOptions' => ['Male', 'Female', 'Other'],
'selectedYear' => $selectedYear,
];
}
public function parentProfiles(): array
{
$allUsers = $this->userModel->findAll();
$parents = [];
// Fetch roles for users in one query to avoid looping over all users
foreach ($allUsers as $user) {
// Get the roles of the user directly
$roles = $this->userRoleModel->getRolesByUserId($user['id']);
$isParent = false;
// Check if $roles is iterable and contains the 'parent' role
if (is_array($roles)) {
foreach ($roles as $role) {
if (isset($role['role_name']) && $role['role_name'] === 'parent') {
$isParent = true;
break;
}
}
}
if ($isParent) {
// Retrieve the latest paid amount and balance for this parent
$paidAmount = $this->invoiceModel->getLatestInvoicePaidAmount($user['id']) ?? 0;
$balance = $this->invoiceModel->getLatestInvoiceBalance($user['id']) ?? 0;
// Get students for this parent
$studentsData = $this->studentModel->where('parent_id', $user['id'])->findAll();
$students = [];
foreach ($studentsData as $student) {
$classSectionName = $this->studentClassModel->getClassSectionNameByStudentId($student['id']) ?? 'N/A';
$students[] = [
'name' => $student['firstname'] . ' ' . $student['lastname'],
'class_section' => $classSectionName
];
}
// Add parent data to the array
$parents[] = [
'id' => $user['id'],
'school_id' => $user['school_id'],
'firstname' => $user['firstname'],
'lastname' => $user['lastname'],
'email' => $user['email'],
'cellphone' => $user['cellphone'],
'gender' => $user['gender'],
'created_at' => $user['created_at'],
'paid_amount' => $paidAmount,
'balance' => $balance,
'students' => $students,
];
}
}
return ['parents' => $parents];
}
}