recreate project
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Calculators;
|
||||
|
||||
use App\Interfaces\ScoreCalculatorInterface;
|
||||
use App\Models\AttendanceRecordModel;
|
||||
use App\Models\ConfigurationModel;
|
||||
use App\Models\CalendarModel;
|
||||
use RuntimeException;
|
||||
|
||||
class AttendanceCalculator implements ScoreCalculatorInterface
|
||||
{
|
||||
private $attendanceModel;
|
||||
private $configModel;
|
||||
private $calendarModel;
|
||||
|
||||
public function __construct(
|
||||
AttendanceRecordModel $attendanceModel,
|
||||
ConfigurationModel $configModel,
|
||||
CalendarModel $calendarModel
|
||||
) {
|
||||
$this->attendanceModel = $attendanceModel;
|
||||
$this->configModel = $configModel;
|
||||
$this->calendarModel = $calendarModel;
|
||||
}
|
||||
|
||||
public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array
|
||||
{
|
||||
$absences = $this->attendanceModel->getTotalAbsences($studentId, $semester, $schoolYear);
|
||||
|
||||
$totalDays = null;
|
||||
$normSemester = $this->normalizeSemester($semester);
|
||||
if ($schoolYear !== '' && $normSemester !== '') {
|
||||
$semRange = $this->getSemesterRange($schoolYear, $normSemester);
|
||||
if ($semRange) {
|
||||
try {
|
||||
$events = $this->calendarModel->getEventsBySchoolYearAndSemester($schoolYear, $normSemester);
|
||||
$noSchoolSundays = 0;
|
||||
foreach ($events as $event) {
|
||||
if (!empty($event['no_school'])) {
|
||||
$date = new \DateTime($event['date']);
|
||||
if ($date->format('N') == 7) {
|
||||
if ($date->format('Y-m-d') >= $semRange[0] && $date->format('Y-m-d') <= $semRange[1]) {
|
||||
$noSchoolSundays++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$totalDays = $this->countSundays($semRange[0], $semRange[1]) - $noSchoolSundays;
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Failed to count sundays for attendance score: ' . $e->getMessage());
|
||||
$totalDays = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($totalDays === null) {
|
||||
$totalDays = $this->getConfiguredSemesterLength($semester);
|
||||
} else {
|
||||
$configuredDays = $this->getConfiguredSemesterLength($semester);
|
||||
if ($configuredDays !== null) {
|
||||
$totalDays = $configuredDays;
|
||||
}
|
||||
}
|
||||
|
||||
if ($absences === null || $totalDays === null || $totalDays < 0) {
|
||||
throw new RuntimeException("Invalid attendance data: could not determine total days or absences for student {$studentId}.");
|
||||
}
|
||||
|
||||
if ($totalDays == 0) {
|
||||
return ['attendance_score' => 100.0];
|
||||
}
|
||||
|
||||
$attendanceRatio = ($totalDays + 1 - $absences) / $totalDays;
|
||||
$score = min(100, max(0, $attendanceRatio * 100));
|
||||
|
||||
return ['attendance_score' => round($score, 2)];
|
||||
}
|
||||
|
||||
protected function normalizeSemester(?string $input): string
|
||||
{
|
||||
$s = strtolower(trim((string)$input));
|
||||
if ($s === 'fall' || str_contains($s, '1')) return 'fall';
|
||||
if ($s === 'spring' || str_contains($s, '2')) return 'spring';
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function getSemesterRange(string $schoolYear, string $semester): ?array
|
||||
{
|
||||
$norm = $this->normalizeSemester($semester);
|
||||
if ($norm === '' || !preg_match('/^(\d{4})-(\d{4})$/', trim($schoolYear), $m)) {
|
||||
// Fallback for single year format
|
||||
if ($norm === '' || !preg_match('/^(\d{4})/', trim($schoolYear), $m)) {
|
||||
return null;
|
||||
}
|
||||
$y1 = (int)$m[1];
|
||||
$y2 = $y1 + 1;
|
||||
} else {
|
||||
$y1 = (int)$m[1];
|
||||
$y2 = (int)$m[2];
|
||||
}
|
||||
|
||||
$fallStartCfg = (string)($this->configModel->getConfig('fall_semester_start') ?? '');
|
||||
$fallEndCfg = (string)($this->configModel->getConfig('fall_end_date') ?? '');
|
||||
$springStartCfg = (string)($this->configModel->getConfig('spring_semester_start') ?? '');
|
||||
$springEndCfg = (string)($this->configModel->getConfig('last_school_day') ?? '');
|
||||
|
||||
if ($norm === 'fall') {
|
||||
$start = ($fallStartCfg !== '') ? sprintf('%04d-%s', $y1, date('m-d', strtotime($fallStartCfg))) : "{$y1}-09-01";
|
||||
$end = ($fallEndCfg !== '') ? sprintf('%04d-%s', $y2, date('m-d', strtotime($fallEndCfg))) : "{$y2}-01-15";
|
||||
return [$start, $end];
|
||||
}
|
||||
|
||||
if ($norm === 'spring') {
|
||||
$start = ($springStartCfg !== '') ? sprintf('%04d-%s', $y2, date('m-d', strtotime($springStartCfg))) : "{$y2}-01-16";
|
||||
$end = ($springEndCfg !== '') ? sprintf('%04d-%s', $y2, date('m-d', strtotime($springEndCfg))) : "{$y2}-06-30";
|
||||
return [$start, $end];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function countSundays(string $startDate, string $endDate): int
|
||||
{
|
||||
$start = new \DateTime($startDate);
|
||||
$end = new \DateTime($endDate);
|
||||
$sundays = 0;
|
||||
$interval = new \DateInterval('P1D');
|
||||
$period = new \DatePeriod($start, $interval, $end->modify('+1 day')); // include end date
|
||||
|
||||
foreach ($period as $day) {
|
||||
if ($day->format('N') == 7) {
|
||||
$sundays++;
|
||||
}
|
||||
}
|
||||
return $sundays;
|
||||
}
|
||||
|
||||
private function getConfiguredSemesterLength(string $semester): ?int
|
||||
{
|
||||
$norm = $this->normalizeSemester($semester);
|
||||
if ($norm === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$configKey = $norm === 'fall' ? 'total_semester1_days' : 'total_semester2_days';
|
||||
$value = $this->configModel->getConfig($configKey);
|
||||
if (!is_numeric($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$length = (int) $value;
|
||||
return $length > 0 ? $length : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Calculators;
|
||||
|
||||
use App\Interfaces\ScoreCalculatorInterface;
|
||||
use App\Models\HomeworkModel;
|
||||
|
||||
class HomeworkCalculator implements ScoreCalculatorInterface
|
||||
{
|
||||
private $homeworkModel;
|
||||
|
||||
public function __construct(HomeworkModel $homeworkModel)
|
||||
{
|
||||
$this->homeworkModel = $homeworkModel;
|
||||
}
|
||||
|
||||
public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array
|
||||
{
|
||||
$average = $this->homeworkModel->getAverageHomeworkScore($studentId, $semester, $schoolYear, $classSectionId);
|
||||
|
||||
return ['homework_avg' => $average !== null ? (float) $average : null];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Calculators;
|
||||
|
||||
use App\Interfaces\ScoreCalculatorInterface;
|
||||
use App\Models\ProjectModel;
|
||||
|
||||
class ProjectCalculator implements ScoreCalculatorInterface
|
||||
{
|
||||
private $projectModel;
|
||||
|
||||
public function __construct(ProjectModel $projectModel)
|
||||
{
|
||||
$this->projectModel = $projectModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the average project score for a student
|
||||
*
|
||||
* @param int $studentId
|
||||
* @param string $semester
|
||||
* @param string $schoolYear
|
||||
* @return array Returns ['project_avg' => float|null]
|
||||
* @throws \RuntimeException If no project scores are found
|
||||
*/
|
||||
public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array
|
||||
{
|
||||
$average = $this->projectModel->getAverageProjectScore($studentId, $semester, $schoolYear, $classSectionId);
|
||||
|
||||
return ['project_avg' => $average !== null ? (float) $average : null];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Calculators;
|
||||
|
||||
use App\Interfaces\ScoreCalculatorInterface;
|
||||
use App\Models\QuizModel;
|
||||
|
||||
class QuizCalculator implements ScoreCalculatorInterface
|
||||
{
|
||||
private $quizModel;
|
||||
|
||||
public function __construct(QuizModel $quizModel)
|
||||
{
|
||||
$this->quizModel = $quizModel;
|
||||
}
|
||||
|
||||
public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array
|
||||
{
|
||||
$average = $this->quizModel->getAverageQuizScore($studentId, $semester, $schoolYear, $classSectionId);
|
||||
|
||||
return ['quiz_avg' => $average !== null ? (float) $average : null];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user