95 lines
3.1 KiB
PHP
95 lines
3.1 KiB
PHP
<?php
|
|
|
|
use App\Models\AttendanceCommentTemplateModel;
|
|
|
|
if (!function_exists('attendance_comment_from_score')) {
|
|
function attendance_comment_from_score($score, string $firstName = ''): ?string
|
|
{
|
|
if ($score === null || $score === '') {
|
|
return null;
|
|
}
|
|
|
|
$score = (float) $score;
|
|
$template = attendance_comment_template_for_score($score);
|
|
if ($template === null) {
|
|
return null;
|
|
}
|
|
|
|
$text = trim((string) ($template['template_text'] ?? ''));
|
|
if ($text === '') {
|
|
return null;
|
|
}
|
|
|
|
$name = trim($firstName) !== '' ? trim($firstName) : 'This student';
|
|
$lastChar = $name !== '' ? substr($name, -1) : '';
|
|
$namePossessive = ($name === 'This student')
|
|
? "This student's"
|
|
: ($lastChar === 's' || $lastChar === 'S' ? ($name . "'") : ($name . "'s"));
|
|
if (strpos($text, '{name}') !== false) {
|
|
return str_replace('{name}', $namePossessive, $text);
|
|
}
|
|
|
|
return $namePossessive . ' ' . $text;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('attendance_comment_template_for_score')) {
|
|
function attendance_comment_template_for_score(float $score): ?array
|
|
{
|
|
static $templates = null;
|
|
|
|
if ($templates === null) {
|
|
try {
|
|
$model = new AttendanceCommentTemplateModel();
|
|
$templates = $model->getActiveTemplates();
|
|
} catch (\Throwable $e) {
|
|
$templates = [];
|
|
}
|
|
}
|
|
|
|
return attendance_comment_template_match($templates, $score);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('attendance_comment_template_match')) {
|
|
function attendance_comment_template_match(array $templates, float $score): ?array
|
|
{
|
|
if ($templates === []) {
|
|
return null;
|
|
}
|
|
|
|
// Attendance scores are percentage values; clamp to the expected domain
|
|
// so minor calculation drift above 100 or below 0 does not skip a template.
|
|
$score = max(0.0, min(100.0, $score));
|
|
|
|
usort($templates, static function (array $a, array $b): int {
|
|
$aMin = isset($a['min_score']) ? (float) $a['min_score'] : 0.0;
|
|
$bMin = isset($b['min_score']) ? (float) $b['min_score'] : 0.0;
|
|
|
|
return $aMin <=> $bMin;
|
|
});
|
|
|
|
foreach ($templates as $template) {
|
|
$min = isset($template['min_score']) ? (float) $template['min_score'] : 0.0;
|
|
$max = isset($template['max_score']) ? (float) $template['max_score'] : 100.0;
|
|
if ($score >= $min && $score <= $max) {
|
|
return $template;
|
|
}
|
|
}
|
|
|
|
// Some configured bands use integer boundaries like 60-69 and 70-79,
|
|
// while attendance scores contain decimals like 69.23. When the score
|
|
// lands in that fractional gap, fall back to the nearest lower band.
|
|
$candidate = null;
|
|
foreach ($templates as $template) {
|
|
$min = isset($template['min_score']) ? (float) $template['min_score'] : 0.0;
|
|
if ($score < $min) {
|
|
break;
|
|
}
|
|
$candidate = $template;
|
|
}
|
|
|
|
return $candidate;
|
|
}
|
|
}
|