Attendance Analysis
= $this->include('partials/academic_filter') ?>
= $this->section('styles') ?>
= $this->endSection() ?>
getGet('start_date') ?? ''));
$endDateRaw = trim((string)($req->getGet('end_date') ?? ''));
$isValidDate = static function (string $d): bool {
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $d)) return false;
[$y, $m, $day] = array_map('intval', explode('-', $d));
return checkdate($m, $day, $y);
};
$filterStart = ($startDateRaw !== '' && $isValidDate($startDateRaw)) ? $startDateRaw : '';
$filterEnd = ($endDateRaw !== '' && $isValidDate($endDateRaw)) ? $endDateRaw : '';
// ---- Build labels and a stable order: KG -> Grade 1..12 -> Youth ----
$labelsByClassId = [];
$gradeNumberById = [];
$kgIds = [];
$arabicIds = [];
$youthIds = [];
foreach ($grades as $classId => $sections) {
$cid = (int)$classId;
$sampleName = '';
$isArabicProgram = false;
foreach ($sections as $s) {
$sampleName = (string)($s['class_section_name'] ?? '');
$lowName = strtolower($sampleName);
$lowCode = strtolower((string)($s['class_section_id'] ?? ''));
if (strpos($lowName, 'arabic') !== false || strpos($lowCode, 'arabic') !== false) {
$isArabicProgram = true;
}
if ($sampleName !== '') break;
}
if ($isArabicProgram || $cid === 14) {
$labelsByClassId[$cid] = 'Arabic';
$arabicIds[] = $cid;
} elseif (preg_match('/\bKG\b/i', $sampleName)) {
$labelsByClassId[$cid] = 'KG';
$kgIds[] = $cid;
} elseif (preg_match('/\bYouth\b/i', $sampleName)) {
$labelsByClassId[$cid] = 'Youth';
$youthIds[] = $cid;
} elseif (preg_match('/Grade\s*(\d+)/i', $sampleName, $m)) {
$labelsByClassId[$cid] = 'Grade ' . (int)$m[1];
$gradeNumberById[$cid] = (int)$m[1];
} else {
if ($cid === 0) {
$labelsByClassId[$cid] = 'KG';
$kgIds[] = $cid;
} elseif ($cid === 13) {
$labelsByClassId[$cid] = 'Youth';
$youthIds[] = $cid;
} else {
$labelsByClassId[$cid] = 'Grade ' . $cid;
$gradeNumberById[$cid] = $cid;
}
}
}
$sortedClassIds = [];
if ($kgIds) {
sort($kgIds, SORT_NUMERIC);
$sortedClassIds = array_merge($sortedClassIds, $kgIds);
}
if ($gradeNumberById) {
asort($gradeNumberById, SORT_NUMERIC);
$sortedClassIds = array_merge($sortedClassIds, array_keys($gradeNumberById));
}
if ($youthIds) {
sort($youthIds, SORT_NUMERIC);
$sortedClassIds = array_merge($sortedClassIds, $youthIds);
}
if ($arabicIds) {
sort($arabicIds, SORT_NUMERIC);
$sortedClassIds = array_merge($sortedClassIds, $arabicIds);
}
$presentIds = array_map('intval', array_keys($grades));
$missingIds = array_values(array_diff($presentIds, $sortedClassIds));
if (!empty($missingIds)) {
$sortedClassIds = array_merge($sortedClassIds, $missingIds);
}
$labelFor = function (int $id) use ($labelsByClassId): string {
return $labelsByClassId[$id] ?? ('Class ' . $id);
};
// ---- Attendance analysis ----
$analysisOverall = ['present' => 0, 'late' => 0, 'absent' => 0];
$analysisByGrade = [];
$analysisBySection = [];
$analysisTotal = 0;
foreach ($grades as $classId => $sections) {
$gradeLabel = $labelFor((int)$classId);
if (!isset($analysisByGrade[$gradeLabel])) {
$analysisByGrade[$gradeLabel] = ['present' => 0, 'late' => 0, 'absent' => 0];
}
foreach ($sections as $section) {
$sectionKey = (string)($section['class_section_id'] ?? ($section['id'] ?? ''));
if ($sectionKey === '' || empty($studentsBySection[$sectionKey])) continue;
$secNameRaw = trim((string)($section['class_section_name'] ?? ''));
$secLabel = $secNameRaw !== '' ? $secNameRaw : ('Section ' . $sectionKey);
if (!isset($analysisBySection[$secLabel])) {
$analysisBySection[$secLabel] = ['present' => 0, 'late' => 0, 'absent' => 0, 'total_students' => 0];
}
$sectionTotalStudents = count($studentsBySection[$sectionKey]);
if ($sectionTotalStudents > ($analysisBySection[$secLabel]['total_students'] ?? 0)) {
$analysisBySection[$secLabel]['total_students'] = $sectionTotalStudents;
}
foreach ($studentsBySection[$sectionKey] as $stu) {
$sid = (int)($stu['id'] ?? 0);
if ($sid <= 0) continue;
$entries = $attendanceData[$sectionKey][$sid] ?? [];
if (!is_array($entries)) continue;
foreach ($entries as $e) {
$d = substr((string)($e['date'] ?? ''), 0, 10);
if ($d === '') continue;
if ($filterStart !== '' && $d < $filterStart) continue;
if ($filterEnd !== '' && $d > $filterEnd) continue;
$st = strtolower(trim((string)($e['status'] ?? '')));
if (!in_array($st, ['present', 'late', 'absent'], true)) continue;
$analysisOverall[$st]++;
$analysisByGrade[$gradeLabel][$st]++;
$analysisBySection[$secLabel][$st]++;
$analysisTotal++;
}
}
}
}
$overallPercent = [];
foreach (['present', 'late', 'absent'] as $st) {
$overallPercent[$st] = $analysisTotal > 0 ? round(($analysisOverall[$st] * 100) / $analysisTotal, 1) : 0;
}
$analysisGradeLabels = [];
$analysisGradeAbsent = [];
$analysisGradeLate = [];
$analysisGradeTotals = [];
foreach ($sortedClassIds as $cid) {
$lbl = $labelFor((int)$cid);
$g = $analysisByGrade[$lbl] ?? ['present' => 0, 'late' => 0, 'absent' => 0];
$analysisGradeLabels[] = $lbl;
$analysisGradeAbsent[] = (int)($g['absent'] ?? 0);
$analysisGradeLate[] = (int)($g['late'] ?? 0);
$analysisGradeTotals[] = (int)($g['present'] ?? 0) + (int)($g['late'] ?? 0) + (int)($g['absent'] ?? 0);
}
$analysisSectionLabels = array_keys($analysisBySection);
$analysisSectionAbsent = [];
$analysisSectionLate = [];
$analysisSectionTotals = [];
foreach ($analysisSectionLabels as $lbl) {
$s = $analysisBySection[$lbl] ?? ['present' => 0, 'late' => 0, 'absent' => 0];
$analysisSectionAbsent[] = (int)($s['absent'] ?? 0);
$analysisSectionLate[] = (int)($s['late'] ?? 0);
$analysisSectionTotals[] = (int)($s['total_students'] ?? 0);
}
$totalDaysForPercent = 0;
if ($filterStart === '' && $filterEnd === '' && !empty($totalPassedDays)) {
$totalDaysForPercent = (int)$totalPassedDays;
} elseif (!empty($dateList) && is_array($dateList)) {
foreach ($dateList as $d) {
$d = (string)$d;
if ($d === '') continue;
if ($filterStart !== '' && $d < $filterStart) continue;
if ($filterEnd !== '' && $d > $filterEnd) continue;
if (!empty($noSchoolDays[$d])) continue;
$totalDaysForPercent++;
}
}
$backUrl = site_url('administrator/daily_attendance');
$queryParts = [];
if (!empty($semester)) $queryParts[] = 'semester=' . urlencode((string)$semester);
if (!empty($schoolYear)) $queryParts[] = 'school_year=' . urlencode((string)$schoolYear);
if ($queryParts) $backUrl .= '?' . implode('&', $queryParts);
?>
Overall Distribution
| Status |
Count |
Percent |
| Present |
= (int)$analysisOverall['present'] ?> |
= number_format($overallPercent['present'], 1) ?>% |
| Late |
= (int)$analysisOverall['late'] ?> |
= number_format($overallPercent['late'], 1) ?>% |
| Absent |
= (int)$analysisOverall['absent'] ?> |
= number_format($overallPercent['absent'], 1) ?>% |
By Section (Absent / Late)