Files
alrahma_sunday_school_api/app/Services/Grading/Validation/GradebookFinalizationValidator.php
T
2026-06-09 01:25:14 -04:00

100 lines
3.7 KiB
PHP

<?php
namespace App\Services\Grading\Validation;
use Illuminate\Support\Facades\DB;
class GradebookFinalizationValidator
{
/**
* Strong-mode validation only. Legacy mode deliberately remains displayable/lockable
* so historical records are not reinterpreted by the new policy.
*/
public function validateClassSectionBeforeLock(int $classSectionId, string $semester, string $schoolYear): array
{
$errors = [];
foreach ($this->scoreTables() as $table => $meta) {
if (! DB::getSchemaBuilder()->hasTable($table)) {
continue;
}
$query = DB::table($table)
->where('class_section_id', $classSectionId)
->where('semester', $semester)
->where('school_year', $schoolYear);
if (DB::getSchemaBuilder()->hasColumn($table, 'status')) {
$pending = (clone $query)->where(function ($q) {
$q->whereNull('status')->orWhere('status', 'pending');
})->get();
foreach ($pending as $row) {
$errors[] = $this->error($table, $meta['category'], $row, 'pending_score', 'Score must be marked scored, missing, excused, or not_assigned before strong-mode lock.');
}
}
if (DB::getSchemaBuilder()->hasColumn($table, 'max_points')) {
$invalidMax = (clone $query)->where(function ($q) {
$q->whereNull('max_points')->orWhere('max_points', '<=', 0);
})->get();
foreach ($invalidMax as $row) {
$errors[] = $this->error($table, $meta['category'], $row, 'invalid_max_points', 'Max points must be greater than 0.');
}
$invalidScores = (clone $query)
->whereNotNull('score')
->where(function ($q) {
$q->where('score', '<', 0)->orWhereRaw('score > max_points');
})
->get();
foreach ($invalidScores as $row) {
$errors[] = $this->error($table, $meta['category'], $row, 'score_out_of_range', 'Score must be between 0 and max_points.');
}
} else {
$invalidScores = (clone $query)
->whereNotNull('score')
->where(function ($q) {
$q->where('score', '<', 0)->orWhere('score', '>', 100);
})
->get();
foreach ($invalidScores as $row) {
$errors[] = $this->error($table, $meta['category'], $row, 'score_out_of_range', 'Score must be between 0 and 100.');
}
}
}
return [
'valid' => empty($errors),
'errors' => $errors,
];
}
private function scoreTables(): array
{
return [
'homework' => ['category' => 'homework'],
'quiz' => ['category' => 'quiz'],
'project' => ['category' => 'project'],
'participation' => ['category' => 'participation'],
'midterm_exam' => ['category' => 'midterm_exam'],
'final_exam' => ['category' => 'final_exam'],
];
}
private function error(string $table, string $category, object $row, string $code, string $message): array
{
return [
'table' => $table,
'category' => $category,
'student_id' => isset($row->student_id) ? (int) $row->student_id : null,
'item_index' => $row->homework_index ?? $row->quiz_index ?? $row->project_index ?? null,
'code' => $code,
'message' => $message,
];
}
}