Files
alrahma_sunday_school_api/app/Services/AssignmentService.php
T
2026-03-05 12:29:37 -05:00

283 lines
11 KiB
PHP

<?php
namespace App\Services;
use App\Models\ClassSection;
use App\Models\Configuration;
use App\Models\Student;
use App\Models\StudentClass;
use App\Models\TeacherClass;
use App\Models\User;
use Illuminate\Support\Facades\DB;
class AssignmentService
{
public function __construct(
protected User $userModel,
protected Configuration $configModel,
protected Student $studentModel,
protected ClassSection $classSectionModel,
protected TeacherClass $teacherClassModel,
protected StudentClass $studentClassModel
) {}
public function buildClassAssignments(array $filters = []): array
{
$currentSemester = (string) ($this->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] : [];
}
}