'Fall', 'spring' => 'Spring', default => '', }; } public function getSchoolYearRange(string $schoolYear): array { [$startYear, $endYear] = $this->parseSchoolYear($schoolYear); $config = $this->ensureAttendanceConfigs($schoolYear); return [ Carbon::parse($config['school_year_start'] ?? Carbon::create($startYear, 9, 1)->toDateString())->toDateString(), Carbon::parse($config['last_school_day'])->toDateString(), ]; } public function getSemesterRange(string $schoolYear, string $semester): ?array { $semester = $this->normalizeSemester($semester); $config = $this->ensureAttendanceConfigs($schoolYear); $fallStart = $config['fall_semester_start']; $springStart = $config['spring_semester_start']; $lastDay = $config['last_school_day']; if ($semester === 'Fall' && $fallStart && $springStart) { return [ Carbon::parse($fallStart)->toDateString(), Carbon::parse($springStart)->subDay()->toDateString(), ]; } if ($semester === 'Spring' && $springStart && $lastDay) { return [ Carbon::parse($springStart)->toDateString(), Carbon::parse($lastDay)->toDateString(), ]; } return null; } public function buildSundayList(string $startDate, string $endDate): array { $start = Carbon::parse($startDate)->startOfDay(); $end = Carbon::parse($endDate)->startOfDay(); if ($start->dayOfWeek !== Carbon::SUNDAY) { $start = $start->next(Carbon::SUNDAY); } $dates = []; $cursor = $start->copy(); while ($cursor->lte($end)) { $dates[] = $cursor->toDateString(); $cursor->addWeek(); } return $dates; } protected function parseSchoolYear(string $schoolYear): array { if (preg_match('/^\s*(\d{4})\s*-\s*(\d{4})\s*$/', $schoolYear, $m)) { return [(int) $m[1], (int) $m[2]]; } $configured = trim((string) $this->getConfig('school_year')); if (preg_match('/^\s*(\d{4})\s*-\s*(\d{4})\s*$/', $configured, $m)) { return [(int) $m[1], (int) $m[2]]; } $year = (int) date('Y'); $derived = $year.'-'.($year + 1); $this->setConfig('school_year', $derived); return [$year, $year + 1]; } /** * Ensure the attendance range config keys exist in `configuration`. * * @return array{ * school_year:string, * fall_semester_start:string, * spring_semester_start:string, * last_school_day:string * } */ protected function ensureAttendanceConfigs(string $schoolYear): array { [$startYear, $endYear] = $this->parseSchoolYear($schoolYear); $resolvedSchoolYear = trim($schoolYear); if ($resolvedSchoolYear === '') { $resolvedSchoolYear = sprintf('%04d-%04d', $startYear, $endYear); } $defaults = [ 'school_year' => $resolvedSchoolYear, 'school_year_start' => Carbon::create($startYear, 9, 1)->toDateString(), 'fall_semester_start' => Carbon::create($startYear, 9, 21)->toDateString(), 'spring_semester_start' => Carbon::create($endYear, 1, 19)->toDateString(), 'last_school_day' => Carbon::create($endYear, 5, 31)->toDateString(), ]; $resolved = []; foreach ($defaults as $key => $defaultValue) { $value = $key === 'school_year_start' ? '' : trim((string) $this->getConfig($key)); if ($value === '') { if ($key !== 'school_year_start') { $this->setConfig($key, $defaultValue); } $value = $defaultValue; } $resolved[$key] = $value; } return $resolved; } private function getConfig(string $key): ?string { try { return Configuration::getConfig($key); } catch (\Throwable) { return null; } } private function setConfig(string $key, string $value): void { try { Configuration::setConfigValueByKey($key, $value); } catch (\Throwable) { // Pure unit tests may use this service without a Laravel container. } } }