Passed
Push — master ( 748ac9...30f06f )
by Marcel
07:58
created

SuggestionResolver::filterAbsencesWithAreExcused()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
nc 1
nop 1
dl 0
loc 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace App\Book\AbsenceSuggestion;
4
5
use App\Dashboard\Absence\AbsenceResolver;
6
use App\Dashboard\AbsentExamStudent;
7
use App\Dashboard\AbsentStudent;
8
use App\Dashboard\AbsentStudentWithAbsenceNote;
9
use App\Entity\LessonAttendanceExcuseStatus;
10
use App\Entity\StudyGroupMembership;
11
use App\Entity\Tuition;
12
use App\Repository\ExcuseNoteRepositoryInterface;
13
use App\Repository\LessonAttendanceRepositoryInterface;
14
use App\Response\Api\V1\Student;
15
use App\Section\SectionResolverInterface;
16
use DateTime;
17
18
class SuggestionResolver {
19
    public function __construct(private readonly AbsenceResolver $absenceResolver, private readonly LessonAttendanceRepositoryInterface $attendanceRepository,
20
                                private readonly ExcuseNoteRepositoryInterface $excuseNoteRepository, private readonly SectionResolverInterface $sectionResolver) {
21
22
    }
23
24
    public function resolve(Tuition $tuition, DateTime $date, int $lesson) {
25
        $students = $tuition->getStudyGroup()->getMemberships()->map(fn(StudyGroupMembership $membership) => $membership->getStudent())->toArray();
26
27
        $suggestions = [ ];
28
29
        $absences = $this->absenceResolver->resolve($date, $lesson, $students);
30
31
        foreach($this->filterAbsencesWithAreExcused($absences) as $absentStudent) {
32
            if(array_key_exists($absentStudent->getStudent()->getId(), $suggestions)) {
33
                continue; // prevent duplicates
34
            }
35
36
            $excuseStatus = ($absentStudent instanceof AbsentStudentWithAbsenceNote && $absentStudent->getAbsence()->getType()->isAlwaysExcused()) ? LessonAttendanceExcuseStatus::Excused : LessonAttendanceExcuseStatus::NotSet;
37
38
            $suggestions[$absentStudent->getStudent()->getId()] = [
39
                'student' => Student::fromEntity($absentStudent->getStudent(), $this->sectionResolver->getCurrentSection()),
40
                'reason' => $absentStudent->getReason()->value,
41
                'label' => $absentStudent->getAbsence()->getType()->getName(),
42
                'zero_absent_lessons' => $absentStudent->getAbsence()->getType()->isTypeWithZeroAbsenceLessons(),
43
                'excuse_status' => $excuseStatus
44
            ];
45
        }
46
47
        foreach($this->filterAbsencesWithoutZeroAbsenceLessons($absences) as $absentStudent) {
48
            if(array_key_exists($absentStudent->getStudent()->getId(), $suggestions)) {
49
                continue; // prevent duplicates
50
            }
51
52
            $excuseStatus = ($absentStudent instanceof AbsentStudentWithAbsenceNote && $absentStudent->getAbsence()->getType()->isAlwaysExcused()) ? LessonAttendanceExcuseStatus::Excused : LessonAttendanceExcuseStatus::NotSet;
53
54
            $suggestions[$absentStudent->getStudent()->getId()] = [
55
                'student' => Student::fromEntity($absentStudent->getStudent(), $this->sectionResolver->getCurrentSection()),
56
                'reason' => $absentStudent->getReason()->value,
57
                'label' => $absentStudent->getAbsence()->getType()->getName(),
58
                'zero_absent_lessons' => false,
59
                'excuse_status' => $excuseStatus
60
            ];
61
        }
62
63
        // Absence in previous lesson
64
        foreach($this->attendanceRepository->findAbsentByStudentsAndDate($students, $date) as $attendance) {
65
            if(array_key_exists($attendance->getStudent()->getId(), $suggestions)) {
66
                continue; // prevent duplicates
67
            }
68
69
            if($attendance->getEntry()->getLessonEnd() < $lesson) {
70
                $suggestions[$attendance->getStudent()->getId()] = [
71
                    'student' => Student::fromEntity($attendance->getStudent(), $this->sectionResolver->getCurrentSection()),
72
                    'reason' => 'absent_before'
73
                ];
74
            }
75
        }
76
77
        // Exam
78
        foreach($this->filterAbsencesWithExam($absences) as $absentExamStudent) {
79
            if(array_key_exists($absentExamStudent->getStudent()->getId(), $suggestions)) {
80
                continue; // prevent duplicates
81
            }
82
83
            if($absentExamStudent->getExam()->getTuitions()->count() === 1 && $absentExamStudent->getExam()->getTuitions()->first() === $tuition) {
84
                continue; // do not show exam of current tuition
85
            }
86
87
            $suggestions[$absentExamStudent->getStudent()->getId()] = [
88
                'student' => Student::fromEntity($absentExamStudent->getStudent(), $this->sectionResolver->getCurrentSection()),
89
                'reason' => $absentExamStudent->getReason()->value,
90
                'zero_absent_lessons' => true,
91
                'excuse_status' => LessonAttendanceExcuseStatus::Excused
92
            ];
93
        }
94
95
        // Absences with zero absent lessons
96
        foreach($this->filterAbsencesWithZeroAbsenceLessons($absences) as $absentStudent) {
97
            if(array_key_exists($absentStudent->getStudent()->getId(), $suggestions)) {
98
                continue; // prevent duplicates
99
            }
100
101
            $excuseStatus = ($absentStudent instanceof AbsentStudentWithAbsenceNote && $absentStudent->getAbsence()->getType()->isAlwaysExcused()) ? LessonAttendanceExcuseStatus::Excused : LessonAttendanceExcuseStatus::NotSet;
102
103
            $suggestions[$absentStudent->getStudent()->getId()] = [
104
                'student' => Student::fromEntity($absentStudent->getStudent(), $this->sectionResolver->getCurrentSection()),
105
                'reason' => $absentStudent->getReason()->value,
106
                'label' => $absentStudent->getAbsence()->getType()->getName(),
107
                'zero_absent_lessons' => true,
108
                'excuse_status' => $excuseStatus
109
            ];
110
        }
111
112
        // Excuse
113
        foreach($this->excuseNoteRepository->findByStudentsAndDate($students, $date) as $note) {
114
            if(array_key_exists($note->getStudent()->getId(), $suggestions)) {
115
                continue; // prevent duplicates
116
            }
117
118
            if($note->appliesToLesson($date, $lesson)) {
119
                $suggestions[$note->getStudent()->getId()] = [
120
                    'student' => Student::fromEntity($note->getStudent(), $this->sectionResolver->getCurrentSection()),
121
                    'reason' => 'excuse',
122
                    'excuse_status' => LessonAttendanceExcuseStatus::Excused
123
                ];
124
            }
125
        }
126
127
        return array_values($suggestions);
128
    }
129
130
    /**
131
     * @param AbsentStudent[] $students
132
     * @return AbsentStudentWithAbsenceNote[]
133
     */
134
    private function filterAbsencesWithoutZeroAbsenceLessons(array $students): array {
135
        return array_filter($students, fn(AbsentStudent $absentStudent) => ($absentStudent instanceof AbsentStudentWithAbsenceNote && !$absentStudent->getAbsence()->getType()->isTypeWithZeroAbsenceLessons()));
136
    }
137
138
    /**
139
     * @param AbsentStudent[] $students
140
     * @return AbsentExamStudent[]
141
     */
142
    private function filterAbsencesWithExam(array $students): array {
143
        return array_filter($students, fn(AbsentStudent $absentStudent) => $absentStudent instanceof AbsentExamStudent);
144
    }
145
146
    /**
147
     * @param AbsentStudent[] $students
148
     * @return AbsentStudentWithAbsenceNote[]
149
     */
150
    private function filterAbsencesWithZeroAbsenceLessons(array $students): array {
151
        return array_filter($students, fn(AbsentStudent $absentStudent) => ($absentStudent instanceof AbsentStudentWithAbsenceNote && $absentStudent->getAbsence()->getType()->isTypeWithZeroAbsenceLessons()));
152
    }
153
154
    private function filterAbsencesWithAreExcused(array $students): array {
155
        return array_filter($students, fn(AbsentStudent $absentStudent) => $absentStudent instanceof AbsentStudentWithAbsenceNote && $absentStudent->getAbsence()->getType()->isAlwaysExcused());
156
    }
157
}