111 lines
3.8 KiB
PHP
111 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Incidents;
|
|
|
|
use App\Models\Incident;
|
|
|
|
class IncidentAnalysisService
|
|
{
|
|
public function __construct(private IncidentLookupService $lookup) {}
|
|
|
|
public function analyze(?string $schoolYear, ?string $semester): array
|
|
{
|
|
$builder = Incident::query()->orderBy('incident_datetime', 'DESC');
|
|
if ($schoolYear !== null && $schoolYear !== '') {
|
|
$builder->where('school_year', $schoolYear);
|
|
}
|
|
if ($semester !== null && $semester !== '') {
|
|
$builder->where('semester', $semester);
|
|
}
|
|
|
|
$incidents = $builder->get()->map(fn ($row) => $row->toArray())->all();
|
|
if (empty($incidents)) {
|
|
return [];
|
|
}
|
|
|
|
$gradeMap = $this->lookup->gradeNameMap(array_column($incidents, 'grade'));
|
|
$students = [];
|
|
|
|
foreach ($incidents as $incident) {
|
|
$studentId = (string) ($incident['student_id'] ?? '');
|
|
$studentName = (string) ($incident['student_name'] ?? '');
|
|
$studentKey = $studentId !== '' ? 'id:'.$studentId : 'name:'.strtolower(trim($studentName));
|
|
|
|
$gradeValue = $incident['grade'] ?? '';
|
|
$gradeLabel = $gradeValue;
|
|
if (is_numeric($gradeValue)) {
|
|
$gradeLabel = $gradeMap[(int) $gradeValue] ?? (string) $gradeValue;
|
|
}
|
|
|
|
if (! isset($students[$studentKey])) {
|
|
$students[$studentKey] = [
|
|
'student_id' => $studentId,
|
|
'student_name' => $studentName,
|
|
'grade' => (string) $gradeLabel,
|
|
'total' => 0,
|
|
'open' => 0,
|
|
'closed' => 0,
|
|
'canceled' => 0,
|
|
'last_incident' => null,
|
|
'logs' => [],
|
|
];
|
|
}
|
|
|
|
$students[$studentKey]['total'] += 1;
|
|
|
|
$state = (string) ($incident['incident_state'] ?? '');
|
|
if ($state === 'Open') {
|
|
$students[$studentKey]['open'] += 1;
|
|
} elseif ($state === 'Closed') {
|
|
$students[$studentKey]['closed'] += 1;
|
|
} elseif ($state === 'Canceled') {
|
|
$students[$studentKey]['canceled'] += 1;
|
|
}
|
|
|
|
if ($students[$studentKey]['last_incident'] === null) {
|
|
$students[$studentKey]['last_incident'] = $this->formatIncidentDate($incident['incident_datetime'] ?? null);
|
|
}
|
|
|
|
$students[$studentKey]['logs'][] = [
|
|
'incident' => $incident['incident'] ?? '',
|
|
'incident_state' => $state,
|
|
'incident_datetime' => $this->formatIncidentDate($incident['incident_datetime'] ?? null),
|
|
'open_description' => $incident['open_description'] ?? null,
|
|
'close_description' => $incident['close_description'] ?? null,
|
|
'cancel_description' => $incident['cancel_description'] ?? null,
|
|
'action_taken' => $incident['action_taken'] ?? null,
|
|
];
|
|
}
|
|
|
|
$studentRows = array_values($students);
|
|
usort($studentRows, function ($a, $b) {
|
|
if ($a['total'] === $b['total']) {
|
|
return strcasecmp($a['student_name'], $b['student_name']);
|
|
}
|
|
|
|
return $b['total'] <=> $a['total'];
|
|
});
|
|
|
|
return $studentRows;
|
|
}
|
|
|
|
private function formatIncidentDate(mixed $value): ?string
|
|
{
|
|
if ($value === null || $value === '') {
|
|
return null;
|
|
}
|
|
|
|
if ($value instanceof \DateTimeInterface) {
|
|
return $value->format('Y-m-d H:i:s');
|
|
}
|
|
|
|
$raw = (string) $value;
|
|
$ts = strtotime($raw);
|
|
if ($ts !== false) {
|
|
return date('Y-m-d H:i:s', $ts);
|
|
}
|
|
|
|
return $raw;
|
|
}
|
|
}
|