031e499819
API CI/CD / Validate (composer + pint) (push) Successful in 3m10s
API CI/CD / Test (PHPUnit) (push) Failing after 6m49s
API CI/CD / Build frontend assets (push) Successful in 1m3s
API CI/CD / Security audit (push) Failing after 1m0s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
118 lines
2.9 KiB
PHP
118 lines
2.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Whatsapp;
|
|
|
|
use App\Models\Configuration;
|
|
use App\Models\StudentClass;
|
|
|
|
class WhatsappContextService
|
|
{
|
|
/** @var array<string,bool> */
|
|
private array $rosterPresenceCache = [];
|
|
|
|
public function schoolYear(?string $override = null): string
|
|
{
|
|
foreach ([
|
|
$override,
|
|
request()->query('school_year'),
|
|
request()->header('X-School-Year'),
|
|
Configuration::getConfig('school_year'),
|
|
] as $candidate) {
|
|
$value = trim((string) ($candidate ?? ''));
|
|
if ($value !== '') {
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
public function semester(?string $override = null): string
|
|
{
|
|
foreach ([
|
|
$override,
|
|
request()->query('semester'),
|
|
request()->header('X-Semester'),
|
|
request()->header('X-Selected-Semester'),
|
|
Configuration::getConfig('semester'),
|
|
] as $candidate) {
|
|
$value = trim((string) ($candidate ?? ''));
|
|
if ($value !== '') {
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* School-year aliases like 2025-2026, 2025/2026, 2025-26, 2025.
|
|
*
|
|
* @return array{0: array<int,string>, 1: string, 2: int}
|
|
*/
|
|
public function schoolYearAliases(string $schoolYear): array
|
|
{
|
|
$trim = trim($schoolYear);
|
|
$normalized = str_replace(["\u{2013}", "\u{2014}", '/'], '-', $trim);
|
|
|
|
if (preg_match('/\b(20\d{2})\b/', $normalized, $m)) {
|
|
$start = (int) $m[1];
|
|
} else {
|
|
$start = (int) date('Y');
|
|
}
|
|
|
|
$end = $start + 1;
|
|
$canonical = $start.'-'.$end;
|
|
|
|
$aliases = [
|
|
$canonical,
|
|
$start.'/'.$end,
|
|
sprintf('%d-%02d', $start, $end % 100),
|
|
(string) $start,
|
|
];
|
|
|
|
return [array_values(array_unique($aliases)), $canonical, $start];
|
|
}
|
|
|
|
/**
|
|
* Semester aliases for filtering.
|
|
*
|
|
* @return array<int,string>
|
|
*/
|
|
public function semesterAliases(string $semester): array
|
|
{
|
|
$s = strtolower(trim($semester));
|
|
if ($s === 'fall') {
|
|
return ['fall', 'sem1', 'semester 1', '1', 'f'];
|
|
}
|
|
if ($s === 'spring') {
|
|
return ['spring', 'sem2', 'semester 2', '2', 's'];
|
|
}
|
|
if ($s === 'summer') {
|
|
return ['summer', 'sem3', '3'];
|
|
}
|
|
|
|
return $s === '' ? [] : [$s];
|
|
}
|
|
|
|
public function hasRosterForYear(string $schoolYear): bool
|
|
{
|
|
$year = trim($schoolYear);
|
|
if ($year === '') {
|
|
return false;
|
|
}
|
|
|
|
if (array_key_exists($year, $this->rosterPresenceCache)) {
|
|
return $this->rosterPresenceCache[$year];
|
|
}
|
|
|
|
$exists = StudentClass::query()
|
|
->where('school_year', $year)
|
|
->exists();
|
|
|
|
$this->rosterPresenceCache[$year] = $exists;
|
|
|
|
return $exists;
|
|
}
|
|
}
|