Files
alrahma_sunday_school_api/app/Http/Controllers/old/ParticipationController.php
T
2026-03-08 16:33:24 -04:00

356 lines
13 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Controllers\View;
use App\Controllers\BaseController;
use CodeIgniter\Controller;
use App\Models\TeacherClassModel;
use App\Models\StudentClassModel;
use App\Models\StudentModel;
use App\Models\ParticipationModel;
use App\Models\ConfigurationModel;
use RuntimeException;
use App\Services\SemesterScoreService;
use Config\Services;
use App\Models\GradingLockModel;
use App\Models\MissingScoreOverrideModel;
class ParticipationController extends BaseController
{
protected $db;
protected $semesterScoreService;
protected $schoolYear; // Declare global variable for the controller
protected $semester;
protected $configModel;
protected $studentModel;
protected $teacherClassModel;
protected $gradingLockModel;
protected $missingScoreOverrideModel;
public function __construct()
{
$this->db = \Config\Database::connect();
$this->configModel = new ConfigurationModel();
$this->studentModel = new StudentModel();
$this->teacherClassModel = new TeacherClassModel();
$this->semesterScoreService = service('semesterScoreService');
$this->schoolYear = $this->configModel->getConfig('school_year');
$this->semester = $this->configModel->getConfig('semester');
$this->gradingLockModel = new GradingLockModel();
$this->missingScoreOverrideModel = new MissingScoreOverrideModel();
}
public function add()
{
// 1) Get class_section_id from the view (POST/GET) with session fallback
$incoming = $this->request->getPost('class_section_id')
?? $this->request->getGet('class_section_id')
?? session()->get('class_section_id');
$classSectionId = (int) ($incoming ?: 0);
if ($classSectionId <= 0) {
return redirect()->back()->with('status', 'Missing class section.');
}
// (Optional) persist for downstream pages
session()->set('class_section_id', $classSectionId);
// (Optional) access check if youre restricting by teacher/TA roles
// if (!$this->canAccessClassSection((int)(session()->get('user_id') ?? 0), $classSectionId)) {
// return redirect()->back()->with('status', 'You do not have access to that class section.');
// }
$semester = $this->getSelectedSemesterFromRequest();
$schoolYear = $this->getSelectedSchoolYearFromRequest() ?? $this->schoolYear;
try {
$result = $this->getSavedScores($classSectionId, $semester, $schoolYear);
$missingOkMap = $this->missingScoreOverrideModel->getOverridesMap($classSectionId, $semester, $schoolYear, 'participation');
return view('teacher/add_participation', [
'students' => $result['students'],
'semester' => $result['semester'],
'schoolYear' => $result['schoolYear'],
'classSectionId' => $classSectionId,
'missingOkMap' => $missingOkMap,
]);
} catch (\Throwable $e) {
return redirect()->back()->with('status', $e->getMessage());
}
}
public function update()
{
$updatedBy = session()->get('user_id');
$scores = $this->request->getPost('final_score');
$classSectionId = session()->get('class_section_id');
if (!is_array($scores)) {
return redirect()->back()->with('error', 'No scores submitted.');
}
$semester = $this->getSelectedSemesterFromRequest();
$schoolYear = $this->getSelectedSchoolYearFromRequest() ?? $this->schoolYear;
$classSectionId = (int) ($classSectionId ?? 0);
if ($classSectionId > 0 && $this->isScoresLocked($classSectionId, $semester, $schoolYear)) {
return redirect()->back()->with('error', 'Scores are locked for this class. Unlock to edit.');
}
$this->saveParticipationScores('participation', $scores, $updatedBy, $classSectionId, $semester, $schoolYear);
$missingOk = $this->request->getPost('missing_ok') ?? [];
$studentIds = array_keys($scores);
$checkedItems = [];
if (is_array($missingOk)) {
foreach ($missingOk as $studentId => $flags) {
$checkedItems[] = [
'student_id' => (int) $studentId,
'item_index' => null,
];
}
}
$this->missingScoreOverrideModel->replaceOverrides(
$classSectionId,
(string) $semester,
(string) $schoolYear,
'participation',
$studentIds,
null,
$checkedItems,
$updatedBy,
true
);
$studentTeacherInfo = $this->studentModel->getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear);
// Call the updateScoresForStudents method
try {
$this->semesterScoreService->updateScoresForStudents($studentTeacherInfo, $semester, $schoolYear);
} catch (RuntimeException $e) {
// Handle error
}
return redirect()->to(base_url('/teacher/addParticipation'))
->with('status', 'Participation scores updated successfully.');
}
public function updateMngt()
{
$scores = $this->request->getPost('final_score');
$updatedBy = $this->request->getPost('teacher_id') ?? session()->get('user_id'); // default to session user
$classSectionId = session()->get('class_section_id');
if (!is_array($scores)) {
return redirect()->back()->with('error', 'No scores submitted.');
}
$semester = $this->getSelectedSemesterFromRequest();
$schoolYear = $this->getSelectedSchoolYearFromRequest() ?? $this->schoolYear;
$classSectionId = (int) ($classSectionId ?? 0);
if ($classSectionId > 0 && $this->isScoresLocked($classSectionId, $semester, $schoolYear)) {
return redirect()->back()->with('error', 'Scores are locked for this class. Unlock to edit.');
}
$this->saveParticipationScores('participation', $scores, $updatedBy, $classSectionId, $semester, $schoolYear);
session()->setFlashdata('status', 'Participation scores updated successfully.');
$studentTeacherInfo = $this->studentModel->getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear);
// Call the updateScoresForStudents method
try {
$this->semesterScoreService->updateScoresForStudents($studentTeacherInfo, $semester, $schoolYear);
} catch (RuntimeException $e) {
// Handle error
}
// ⬇️ Directly call the method and return its view
return $this->showParticipationMngt();
}
public function showParticipationMngt()
{
// Get class_section_id from view (POST/GET) with session fallback
$incoming = $this->request->getPost('class_section_id')
?? $this->request->getGet('class_section_id')
?? session()->get('class_section_id');
$classSectionId = (int) ($incoming ?: 0);
if ($classSectionId <= 0) {
return redirect()->back()->with('status', 'Missing class section.');
}
// OPTIONAL: enforce access like we did for homework/midterm
// if (!$this->canAccessClassSection((int)(session()->get('user_id') ?? 0), $classSectionId)) {
// return redirect()->back()->with('status', 'You do not have access to that class section.');
// }
try {
// Pull roster + saved (participation/midterm) scores for this section/term
// If you have a dedicated participation table, call its getter here instead.
$semester = $this->getSelectedSemesterFromRequest();
$schoolYear = $this->getSelectedSchoolYearFromRequest() ?? $this->schoolYear;
$result = $this->getSavedScores($classSectionId, $semester, $schoolYear);
$scoresLocked = $this->isScoresLocked($classSectionId, $semester, $schoolYear);
return view('grading/participation', [
'students' => $result['students'], // already includes school_id
'semester' => $result['semester'],
'schoolYear' => $result['schoolYear'],
'classSectionId' => $classSectionId,
'scoresLocked' => $scoresLocked,
]);
} catch (\Throwable $e) {
return redirect()->back()->with('status', $e->getMessage());
}
}
private function isScoresLocked(int $classSectionId, string $semester, string $schoolYear): bool
{
return $this->gradingLockModel->isLocked($classSectionId, $semester, $schoolYear);
}
private function saveParticipationScores(string $table, array $scores, int $updatedBy, int $classSectionId, string $semester, string $schoolYear): void
{
$db = \Config\Database::connect();
$builder = $db->table($table);
$now = utc_now();
foreach ($scores as $studentId => $data) {
if (!is_numeric($studentId) || !isset($data['score'])) {
continue;
}
$score = is_numeric($data['score']) ? (float) $data['score'] : null;
$existing = $builder
->where('student_id', $studentId)
->where('class_section_id', $classSectionId)
->where('semester', $semester)
->where('school_year', $schoolYear)
->get()
->getRow();
$dataToSave = [
'student_id' => $studentId,
'class_section_id' => $classSectionId,
'updated_by' => $updatedBy,
'score' => $score,
'semester' => $semester,
'school_year' => $schoolYear,
'updated_at' => $now,
];
if ($existing) {
$builder->where('id', $existing->id)->update($dataToSave);
} else {
$dataToSave['created_at'] = $now;
$builder->insert($dataToSave);
}
}
}
private function getSavedScores(int $classSectionId, string $semester, string $schoolYear): array
{
if ($classSectionId <= 0) {
throw new \InvalidArgumentException('Invalid class section id.');
}
session()->set('class_section_id', $classSectionId);
// Build a DISTINCT roster subquery correctly (no 'DISTINCT' inside select string)
$rosterSub = $this->db->table('student_class')
->select('student_id') // <-- just the column
->distinct() // <-- ask CI4 to add DISTINCT
->where('class_section_id', $classSectionId)
->where('school_year', $schoolYear)
->getCompiledSelect();
// Main query: Students + LEFT JOIN participation for same section/term
$students = $this->db->table('students s')
->select('
s.id AS student_id,
s.school_id,
s.firstname,
s.lastname,
p.score
')
->join("({$rosterSub}) sc", 'sc.student_id = s.id', 'inner', false)
->join(
'participation p',
'p.student_id = s.id
AND p.class_section_id = ' . (int)$classSectionId . '
AND p.semester = ' . $this->db->escape($semester) . '
AND p.school_year = ' . $this->db->escape($schoolYear),
'left',
false
)
->where('s.is_active', 1)
->orderBy('s.lastname', 'ASC')
->orderBy('s.firstname', 'ASC')
->get()
->getResultArray();
return [
'students' => $students,
'semester' => $semester,
'schoolYear' => $schoolYear,
];
}
private function getTeacherSelectedSemester(): string
{
helper('semester_selection_helper');
return selected_teacher_semester();
}
private function getSelectedSemesterFromRequest(): string
{
$semesterParam = $this->request->getPost('semester')
?? $this->request->getGet('semester')
?? $this->request->getGet('filter');
$normalized = $this->normalizeSemesterSelection($semesterParam);
if ($normalized !== '') {
$label = ucfirst($normalized);
$session = session();
$session->set('teacher_scores_selected_semester', $label);
$session->set('semester', $label);
}
return $this->getTeacherSelectedSemester();
}
private function getSelectedSchoolYearFromRequest(): ?string
{
$yearParam = $this->request->getPost('school_year') ?? $this->request->getGet('school_year');
return $this->normalizeSchoolYear($yearParam);
}
private function normalizeSemesterSelection(?string $input): string
{
$value = strtolower(trim((string) $input));
if ($value === 'fall' || str_contains($value, '1')) {
return 'fall';
}
if ($value === 'spring' || str_contains($value, '2')) {
return 'spring';
}
return '';
}
private function normalizeSchoolYear(?string $input): ?string
{
$value = trim((string) $input);
if ($value === '') {
return null;
}
if (preg_match('/^\\d{4}\\s*[-\\/]\\s*\\d{4}$/', $value)) {
return preg_replace('/\\s+/', '', str_replace('/', '-', $value));
}
return null;
}
}