229 lines
9.0 KiB
PHP
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];
|
|
}
|
|
}
|