getConfigValue('semester') ?? ''); $currentSchoolYear = (string) ($this->getConfigValue('school_year') ?? ''); $selectedSemester = (string) ($filters['semester'] ?? $currentSemester); $selectedYear = (string) ($filters['school_year'] ?? $currentSchoolYear); $forApi = (bool) ($filters['for_api'] ?? false); // Teacher classes (year-filtered; no semester filtering like your original code) $teacherQ = $this->teacherClassModel->newQuery(); if ($selectedYear !== '') { $teacherQ->where('school_year', $selectedYear); } $teacherClassesAll = $teacherQ->get()->toArray(); // Student classes (active + year-filtered) $studentQ = method_exists($this->studentClassModel, 'active') ? $this->studentClassModel->active() : $this->studentClassModel->newQuery()->where('is_active', 1); if ($selectedYear !== '') { // If your table is aliased in scopeActive(), you can keep student_class.school_year $studentQ->where('school_year', $selectedYear); } $studentClassesAll = $studentQ->get()->toArray(); // Group teacher and student classes by section $teacherBySection = []; foreach ($teacherClassesAll as $tc) { $secId = (int) ($tc['class_section_id'] ?? 0); if ($secId > 0) { $teacherBySection[$secId][] = $tc; } } $studentsBySection = []; foreach ($studentClassesAll as $sc) { $secId = (int) ($sc['class_section_id'] ?? 0); if ($secId > 0) { $studentsBySection[$secId][] = $sc; } } $allSectionIds = array_values(array_unique(array_merge( array_keys($teacherBySection), array_keys($studentsBySection) ))); $classSections = []; foreach ($allSectionIds as $classSectionId) { $teacherClasses = $teacherBySection[$classSectionId] ?? []; $studentClasses = $studentsBySection[$classSectionId] ?? []; if (empty($teacherClasses) && empty($studentClasses)) { continue; } $classSectionName = $this->resolveClassSectionName($classSectionId); $mainTeachers = []; $teacherAssistants = []; $sectionSemester = ''; $sectionSchoolYear = ''; $description = ''; // Teacher metadata + names foreach ($teacherClasses as $teacherClass) { $teacherId = (int) ($teacherClass['teacher_id'] ?? 0); if ($teacherId > 0) { $teacher = $this->userModel->newQuery()->find($teacherId); if ($teacher) { $teacherName = trim( (string) ($teacher->firstname ?? '') . ' ' . (string) ($teacher->lastname ?? '') ); if ($teacherName !== '') { if (($teacherClass['position'] ?? '') === 'main') { $mainTeachers[] = $teacherName; } elseif (($teacherClass['position'] ?? '') === 'ta') { $teacherAssistants[] = $teacherName; } } } } if ($sectionSemester === '' && !empty($teacherClass['semester'])) { $sectionSemester = (string) $teacherClass['semester']; } if ($sectionSchoolYear === '' && !empty($teacherClass['school_year'])) { $sectionSchoolYear = (string) $teacherClass['school_year']; } if ($description === '' && !empty($teacherClass['description'])) { $description = (string) $teacherClass['description']; } } // Students $students = []; foreach ($studentClasses as $studentClass) { if ($sectionSemester === '' && !empty($studentClass['semester'])) { $sectionSemester = (string) $studentClass['semester']; } if ($sectionSchoolYear === '' && !empty($studentClass['school_year'])) { $sectionSchoolYear = (string) $studentClass['school_year']; } if ($description === '' && !empty($studentClass['description'])) { $description = (string) $studentClass['description']; } $studentId = (int) ($studentClass['student_id'] ?? 0); if ($studentId <= 0) { continue; } $student = $this->studentModel->newQuery() ->where('id', $studentId) ->where('is_active', 1) ->first(); if (!$student) { continue; } $students[] = $forApi ? [ 'id' => (int) $student->id, 'firstname' => (string) ($student->firstname ?? ''), 'lastname' => (string) ($student->lastname ?? ''), 'age' => $student->age ?? null, 'gender' => (string) ($student->gender ?? ''), 'registration_grade' => (string) ($student->registration_grade ?? ''), 'photo_consent' => (bool) ($student->photo_consent ?? false), 'tuition_paid' => (bool) ($student->tuition_paid ?? false), 'school_id' => (string) ($student->school_id ?? ''), ] : [ 'id' => (int) $student->id, 'firstname' => e((string) ($student->firstname ?? '')), 'lastname' => e((string) ($student->lastname ?? '')), 'age' => e((string) ($student->age ?? '')), 'gender' => e((string) ($student->gender ?? '')), 'registration_grade' => e((string) ($student->registration_grade ?? '')), 'photo_consent' => e(((bool) ($student->photo_consent ?? false)) ? 'Yes' : 'No'), 'tuition_paid' => e(((bool) ($student->tuition_paid ?? false)) ? 'Yes' : 'No'), 'school_id' => e((string) ($student->school_id ?? '')), ]; } $classSections[] = [ 'class_section_id' => (int) $classSectionId, 'class_section_name' => (string) $classSectionName, 'main_teachers' => array_values(array_unique($mainTeachers)), 'teacher_assistants' => array_values(array_unique($teacherAssistants)), 'students' => $students, 'semester' => $sectionSemester !== '' ? $sectionSemester : $currentSemester, 'school_year' => $sectionSchoolYear !== '' ? $sectionSchoolYear : $currentSchoolYear, 'description' => $description, ]; } // Sort sections by name usort($classSections, fn ($a, $b) => strcmp( (string) ($a['class_section_name'] ?? ''), (string) ($b['class_section_name'] ?? '') )); $schoolYearsList = $this->getSchoolYearsList($currentSchoolYear); $payload = [ 'classSections' => $classSections, 'schoolYears' => $schoolYearsList, 'selectedYear' => $selectedYear, 'selectedSemester' => $selectedSemester, 'semester' => $currentSemester, 'school_year' => $currentSchoolYear, ]; // If you're using Laravel Sanctum/API only, CSRF may not be needed. // Keep it if your frontend still expects it: if (function_exists('csrf_token')) { $payload['csrfToken'] = csrf_token(); } return $payload; } public function saveStudentAssignment(array $data, ?int $updatedBy = null): mixed { $payload = [ 'student_id' => $data['student_id'], 'class_section_id' => $data['class_section_id'], 'semester' => $data['semester'] ?? $this->getConfigValue('semester'), 'school_year' => $data['school_year'] ?? $this->getConfigValue('school_year'), 'description' => $data['description'] ?? null, 'updated_by' => $updatedBy, ]; // If your StudentClass model supports updateOrCreate: // adjust unique keys as needed (e.g. student_id + school_year + semester) return $this->studentClassModel->newQuery()->updateOrCreate( [ 'student_id' => $payload['student_id'], 'school_year' => $payload['school_year'], 'semester' => $payload['semester'], ], $payload ); } protected function getConfigValue(string $key): mixed { // Match your existing model API if present if (method_exists($this->configModel, 'getConfig')) { return $this->configModel->getConfig($key); } // Generic fallback return $this->configModel->newQuery() ->where('key', $key) ->value('value'); } protected function resolveClassSectionName(int $classSectionId): string { if (method_exists($this->classSectionModel, 'getClassSectionNameBySectionId')) { return (string) ($this->classSectionModel->getClassSectionNameBySectionId($classSectionId) ?? ''); } $section = $this->classSectionModel->newQuery()->find($classSectionId); // Adjust to your actual field(s) return (string) ($section->name ?? $section->title ?? ''); } protected function getSchoolYearsList(string $fallbackYear = ''): array { try { $years = DB::table('teacher_class') ->select('school_year') ->whereNotNull('school_year') ->distinct() ->orderByDesc('school_year') ->pluck('school_year') ->map(fn ($y) => (string) $y) ->filter(fn ($y) => $y !== '') ->values() ->all(); if (!empty($years)) { return $years; } } catch (\Throwable $e) { // fallback below } return $fallbackYear !== '' ? [$fallbackYear] : []; } }