resolveSchoolYear($schoolYear); $semester = $this->resolveSemester($semester); return $this->buildStickerCounts($schoolYear, $semester, null, $this->specialMapWithKg()); } public function listForClass(?string $schoolYear, ?string $semester, int $classSectionId): array { $schoolYear = $this->resolveSchoolYear($schoolYear); $semester = $this->resolveSemester($semester); return $this->buildStickerCounts($schoolYear, $semester, $classSectionId, $this->specialMapWithoutKg()); } private function resolveSchoolYear(?string $schoolYear): string { return $schoolYear && trim($schoolYear) !== '' ? $schoolYear : (string) Configuration::getConfig('school_year'); } private function resolveSemester(?string $semester): string { return $semester && trim($semester) !== '' ? $semester : (string) Configuration::getConfig('semester'); } private function buildStickerCounts(string $schoolYear, string $semester, ?int $classSectionId, array $specialMap): array { $builder = DB::table('student_class as sc') ->select( 'sc.student_id', 's.firstname', 's.lastname', 's.is_new', 'cs.class_section_name AS grade_label' ) ->join('students as s', 's.id', '=', 'sc.student_id') ->join('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id') ->join('classes as c', 'c.id', '=', 'cs.class_id') ->where('sc.school_year', $schoolYear); if ($classSectionId !== null && $classSectionId > 0) { $builder->where('sc.class_section_id', $classSectionId); } $rows = $builder->get()->toArray(); $students = []; $totalPrimary = 0; $totalSecondary = 0; foreach ($rows as $row) { $grade = trim((string) ($row->grade_label ?? '')); if ($grade === '' || $this->isYouth($grade)) { continue; } $isNew = (int) ($row->is_new ?? 0) === 1; [$primary, $secondary] = $this->calculateStickerCounts($grade, $isNew, $specialMap); $totalPrimary += $primary; $totalSecondary += $secondary; $students[] = [ 'student_id' => (int) ($row->student_id ?? 0), 'firstname' => trim((string) ($row->firstname ?? '')), 'lastname' => trim((string) ($row->lastname ?? '')), 'grade_label' => $grade, 'primary_count' => $primary, 'secondary_count' => $secondary, ]; } return [ 'schoolYear' => $schoolYear, 'semester' => $semester, 'classSectionId' => $classSectionId, 'students' => $students, 'totals' => [ 'primary' => $totalPrimary, 'secondary' => $totalSecondary, 'students' => count($students), ], ]; } private function calculateStickerCounts(string $grade, bool $isNew, array $specialMap): array { $primary = 0; $secondary = 0; if (array_key_exists($grade, $specialMap)) { $primary = (int) $specialMap[$grade]; $secondary = 0; } elseif ($this->isUpperBlock($grade)) { if ($isNew) { $primary = 4; $secondary = 0; } else { $primary = $this->isGrade5($grade) ? 3 : 2; $secondary = max(0, 4 - $primary); } } else { $primary = 4; $secondary = 0; } return [$primary, $secondary]; } private function isUpperBlock(string $grade): bool { return (bool) preg_match('/^(3|4|5|6|7|8)(-[AB])?$/', trim($grade)); } private function isGrade5(string $grade): bool { return (bool) preg_match('/^5(\-|$)/', trim($grade)); } private function isYouth(string $grade): bool { return (bool) preg_match('/^youth(?:\b|-)/i', trim($grade)); } private function specialMapWithKg(): array { return [ 'KG' => 1, '1-A' => 3, '1-B' => 4, '2-A' => 5, '2-B' => 5, '9' => 2, ]; } private function specialMapWithoutKg(): array { return [ '1-A' => 3, '1-B' => 4, '2-A' => 5, '2-B' => 5, '9' => 2, ]; } }