Passed
Push — master ( 2daeaa...eba4a8 )
by Marcel
16:01
created

DashboardViewHelper::addAbsentStudyGroup()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 4
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 5
rs 10
ccs 0
cts 2
cp 0
crap 12
1
<?php
2
3
namespace App\Dashboard;
4
5
use App\Dashboard\Absence\AbsenceResolver;
6
use App\Dashboard\Absence\ExamStudentsResolver;
7
use App\Entity\Appointment;
8
use App\Entity\Exam;
9
use App\Entity\ExamSupervision;
10
use App\Entity\FreeTimespan;
11
use App\Entity\Grade;
12
use App\Entity\GradeTeacher;
13
use App\Entity\Message;
14
use App\Entity\MessageScope;
15
use App\Entity\ResourceReservation;
16
use App\Entity\Room;
17
use App\Entity\Student;
18
use App\Entity\StudyGroup;
19
use App\Entity\StudyGroupMembership;
20
use App\Entity\Substitution;
21
use App\Entity\Teacher;
22
use App\Entity\TimetableLesson;
23
use App\Entity\TimetableSupervision;
24
use App\Entity\Tuition;
25
use App\Entity\User;
26
use App\Entity\UserType;
27
use App\Grouping\AbsentStudentGroup;
28
use App\Grouping\AbsentStudentStrategy as AbstentStudentGroupStrategy;
29
use App\Grouping\Grouper;
30
use App\Repository\AbsenceRepositoryInterface;
31
use App\Repository\AppointmentRepositoryInterface;
32
use App\Repository\ExamRepositoryInterface;
33
use App\Repository\FreeTimespanRepositoryInterface;
34
use App\Repository\InfotextRepositoryInterface;
35
use App\Repository\LessonEntryRepositoryInterface;
36
use App\Repository\MessageRepositoryInterface;
37
use App\Repository\ResourceReservationRepositoryInterface;
38
use App\Repository\StudentRepositoryInterface;
39
use App\Repository\StudyGroupRepositoryInterface;
40
use App\Repository\SubstitutionRepositoryInterface;
41
use App\Repository\TeacherAbsenceLessonRepositoryInterface;
42
use App\Repository\TeacherRepositoryInterface;
43
use App\Repository\TimetableLessonRepositoryInterface;
44
use App\Repository\TimetableSupervisionRepositoryInterface;
45
use App\Repository\TuitionRepositoryInterface;
46
use App\Section\SectionResolverInterface;
47
use App\Security\Voter\AbsenceVoter;
48
use App\Security\Voter\AppointmentVoter;
49
use App\Security\Voter\ExamVoter;
50
use App\Security\Voter\MessageVoter;
51
use App\Security\Voter\ResourceReservationVoter;
52
use App\Security\Voter\SubstitutionVoter;
53
use App\Settings\BookSettings;
54
use App\Settings\DashboardSettings;
55
use App\Settings\TimetableSettings;
56
use App\Sorting\AbsentStudentStrategy;
57
use App\Sorting\AbsentStudyGroupStrategy;
58
use App\Sorting\AbsentTeacherStrategy;
59
use App\Sorting\MessageStrategy;
60
use App\Sorting\Sorter;
61
use App\Timetable\TimetableTimeHelper;
62
use App\Utils\ArrayUtils;
63
use App\Utils\StudyGroupHelper;
64
use DateTime;
65
use SchulIT\CommonBundle\Helper\DateHelper;
66
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
67
use Symfony\Component\Validator\Validator\ValidatorInterface;
68
69
class DashboardViewHelper {
70
71
    public function __construct(private SubstitutionRepositoryInterface $substitutionRepository, private ExamRepositoryInterface $examRepository, private TimetableLessonRepositoryInterface $timetableRepository,
72
                                private TimetableSupervisionRepositoryInterface $supervisionRepository, private MessageRepositoryInterface $messageRepository, private InfotextRepositoryInterface $infotextRepository,
73
                                private AbsenceRepositoryInterface $absenceRepository, private StudyGroupRepositoryInterface $studyGroupRepository, private AppointmentRepositoryInterface $appointmentRepository,
74
                                private ResourceReservationRepositoryInterface $roomReservationRepository, private FreeTimespanRepositoryInterface $freeTimespanRepository, private StudyGroupHelper $studyGroupHelper,
75
                                private TimetableTimeHelper $timetableTimeHelper, private Sorter $sorter, private Grouper $grouper, private TimetableSettings $timetableSettings, private DashboardSettings $dashboardSettings,
76
                                private AuthorizationCheckerInterface $authorizationChecker, private ValidatorInterface $validator, private DateHelper $dateHelper, private AbsenceResolver $absenceResolver,
77
                                private SectionResolverInterface $sectionResolver, private readonly TuitionRepositoryInterface $tuitionRepository, private readonly TeacherAbsenceLessonRepositoryInterface $absenceLessonRepository,
78
                                private readonly BookSettings $bookSettings, private readonly LessonEntryRepositoryInterface $lessonEntryRepository, private readonly TeacherRepositoryInterface $teacherRepository, private readonly StudentRepositoryInterface $studentRepository)
79
    {
80
    }
81
82
    public function createViewForRoom(Room $room, DateTime $dateTime): DashboardView {
83
        $view = new DashboardView($dateTime);
84
85
        $this->addTimetableLessons($this->timetableRepository->findAllByRoom($dateTime, $dateTime, $room), $dateTime, $view, true);
86
        $this->addEmptyTimetableLessons($view, $this->timetableSettings->getMaxLessons());
87
88
        $this->addSubstitutions($this->substitutionRepository->findAllForRooms([ $room ], $dateTime), $view, true);
89
        $this->addExams($exams = $this->examRepository->findAllByRoomAndDate($room, $dateTime), $view, null, true);
90
        $this->addRoomReservations($this->roomReservationRepository->findAllByResourceAndDate($room, $dateTime), $view);
91
        $this->addFreeTimespans($this->freeTimespanRepository->findAllByDate($dateTime), $view);
92
        $this->setCurrentLesson($view);
93
94
        return $view;
95
    }
96
97
    public function createViewForTeacher(Teacher $teacher, DateTime $dateTime, bool $includeGradeMessages = false): DashboardView {
98
        $view = new DashboardView($dateTime);
99
100
        $start = $this->timetableSettings->getStartDate(UserType::Teacher);
101
        $end = $this->timetableSettings->getEndDate(UserType::Teacher);
102
103
        if($start !== null && $end !== null && $this->dateHelper->isBetween($dateTime, $start, $end)) {
104
            $this->addTimetableLessons($this->timetableRepository->findAllByTeacher($dateTime, $dateTime, $teacher), $dateTime, $view, true);
105
            $this->addSupervisions($this->supervisionRepository->findAllByTeacher($dateTime, $dateTime, $teacher), $view);
106
            $this->addEmptyTimetableLessons($view, $this->timetableSettings->getMaxLessons());
107
        }
108
109
        $messages = [ ];
110
111
        $section = $this->sectionResolver->getSectionForDate($dateTime);
112
113
        if($includeGradeMessages === true && $section !== null) {
114
            /** @var GradeTeacher $gradeTeacher */
115
            foreach($teacher->getGrades() as $gradeTeacher) {
116
                $studyGroups = $this->studyGroupRepository->findAllByGrades($gradeTeacher->getGrade(), $section);
117
                $messages = array_merge($messages, $this->messageRepository->findBy(MessageScope::Messages, UserType::Student, $dateTime, $studyGroups));
118
            }
119
        }
120
121
        $messages = array_merge($messages, $this->messageRepository->findBy(MessageScope::Messages, UserType::Teacher, $dateTime));
122
123
        $messages = ArrayUtils::createArrayWithKeys($messages, fn(Message $message) => $message->getId());
124
125
        $this->addMessages($messages, $view);
126
127
        $this->addSubstitutions($this->substitutionRepository->findAllForTeacher($teacher, $dateTime), $view, true);
128
        $this->addExams($this->examRepository->findAllByTeacher($teacher, $dateTime, true), $view, $teacher, true);
129
        $this->addInfotexts($dateTime, $view);
130
        $this->addAbsentStudyGroup($this->absenceRepository->findAllStudyGroups($dateTime), $view);
131
        $this->addAbsentTeachers($this->absenceRepository->findAllTeachers($dateTime), $view);
132
        $this->addAppointments($this->appointmentRepository->findAllForTeacher($teacher, $dateTime), $view);
133
        $this->addRoomReservations($this->roomReservationRepository->findAllByTeacherAndDate($teacher, $dateTime), $view);
134
        $this->addFreeTimespans($this->freeTimespanRepository->findAllByDate($dateTime), $view);
135
        $this->setCurrentLesson($view);
136
        $this->addBirthdays($view, $dateTime);
137
138
        return $view;
139
    }
140
141
    public function createViewForStudentOrParent(Student $student, DateTime $dateTime, UserType $userType): DashboardView {
142
        $view = new DashboardView($dateTime);
143
144
        $studyGroups = $this->studyGroupHelper->getStudyGroups([$student])->toArray();
145
146
        $start = $this->timetableSettings->getStartDate($userType);
147
        $end = $this->timetableSettings->getEndDate($userType);
148
149
        if($start !== null && $end !== null && $this->dateHelper->isBetween($dateTime, $start, $end)) {
150
            $this->addTimetableLessons($this->timetableRepository->findAllByStudent($dateTime, $dateTime, $student), $dateTime, $view, false);
151
            $this->addEmptyTimetableLessons($view, $this->timetableSettings->getMaxLessons());
152
        }
153
154
        $section = $this->sectionResolver->getSectionForDate($dateTime);
155
156
        $this->addMessages($this->messageRepository->findBy(MessageScope::Messages, $userType, $dateTime, $studyGroups), $view);
157
        $this->addSubstitutions($this->filterSubstitutionsByGrade($this->substitutionRepository->findAllForStudyGroups($studyGroups, $dateTime), $student->getGrade($section)), $view, false);
158
        $this->addExams($this->examRepository->findAllByStudents([$student], $dateTime, true), $view, null, false);
159
        $this->addInfotexts($dateTime, $view);
160
        $this->addAbsentStudyGroup($this->absenceRepository->findAllStudyGroups($dateTime), $view);
161
        $this->addAbsentTeachers($this->absenceRepository->findAllTeachers($dateTime), $view);
162
        $this->addAppointments($this->appointmentRepository->findAllForStudents([$student], $dateTime), $view);
163
        $this->addFreeTimespans($this->freeTimespanRepository->findAllByDate($dateTime), $view);
164
        $this->setCurrentLesson($view);
165
166
        $this->addExercises($view, $student, $dateTime);
167
168
        return $view;
169
    }
170
171
    public function createViewForUser(User $user, DateTime $dateTime): DashboardView {
172
        $view = new DashboardView($dateTime);
173
174
        $this->addMessages($this->messageRepository->findBy(MessageScope::Messages, $user->getUserType(), $dateTime), $view);
175
        $this->setCurrentLesson($view);
176
        $this->addBirthdays($view, $dateTime);
177
178
        return $view;
179
    }
180
181
    private function addBirthdays(DashboardView $view, DateTime $dateTime): DashboardView {
182
        foreach($this->teacherRepository->findAllByBirthday($dateTime) as $birthdayTeacher) {
183
            if($this->authorizationChecker->isGranted('ROLE_SHOW_BIRTHDAY', $birthdayTeacher)) {
184
                $view->addTeacherBirthday($birthdayTeacher);
185
            }
186
        }
187
188
        foreach($this->studentRepository->findAllByBirthday($dateTime) as $birthdayStudent) {
189
            if($this->authorizationChecker->isGranted('ROLE_SHOW_BIRTHDAY', $birthdayStudent)) {
190
                $view->addStudentBirthday($birthdayStudent);
191
            }
192
        }
193
194
        return $view;
195
    }
196
197
    private function setCurrentLesson(DashboardView $dashboardView): void {
198
        foreach($dashboardView->getLessons() as $lesson) {
199
            $startTime = $this->timetableTimeHelper->getLessonStartDateTime($dashboardView->getDateTime(), $lesson->getLessonNumber());
200
            $endTime = $this->timetableTimeHelper->getLessonEndDateTime($dashboardView->getDateTime(), $lesson->getLessonNumber());
201
            $now = $this->dateHelper->getNow();
202
203
            if($startTime <= $now && $now <= $endTime) {
204
                $lesson->setIsCurrent(true);
205
            }
206
        }
207
    }
208
209
    private function addExercises(DashboardView $view, Student $student, DateTime $date) {
210
        $start = (clone $date)->modify(sprintf('-%d days', $this->bookSettings->getExercisesDays()));
211
        $end = clone $date;
212
        $section = $this->sectionResolver->getSectionForDate($date);
213
        $grade = $student->getGrade($section);
214
215
        if($grade === null) {
216
            return;
217
        }
218
219
        $exerciseView = new ExercisesView($start, $end, $grade);
220
        $exerciseView->setEntriesWithExercises($this->lessonEntryRepository->findAllByStudentWithExercises($student, $start, $end));
221
        $view->setExercises($exerciseView);
222
    }
223
224
    /**
225
     * @param TimetableLesson[] $lessons
226
     */
227
    private function addTimetableLessons(iterable $lessons, DateTime $dateTime, DashboardView $dashboardView, bool $computeAbsences): void {
228
        foreach($lessons as $lesson) {
229
            $lessonStudents = [ ];
230
231
            if($lesson->getTuition() !== null) {
232
                $lessonStudents = $lesson
233
                    ->getTuition()
234
                    ->getStudyGroup()
235
                    ->getMemberships()
236
                    ->map(fn(StudyGroupMembership $membership) => $membership->getStudent())
237
                    ->toArray();
238
            }
239
240
            for($lessonNumber = $lesson->getLessonStart(); $lessonNumber <= $lesson->getLessonEnd(); $lessonNumber++) {
241
                $absentStudents = $computeAbsences ? $this->computeAbsentStudents($lessonStudents, $lessonNumber, $dateTime) : [ ];
242
                $absenceLesson = $this->absenceLessonRepository->findOneForLesson($lesson);
243
                $dashboardView->addItem($lessonNumber, new TimetableLessonViewItem($lesson, $absentStudents, $absenceLesson));
244
            }
245
        }
246
    }
247
248
    private function addEmptyTimetableLessons(DashboardView $view, int $numberOfLessons) {
249
        $lessons = $view->getLessonNumbers();
250
251
        for($i = 1; $i <= $numberOfLessons; $i++) {
252
            if(!in_array($i, $lessons)) {
253
                $view->addItem($i, new TimetableLessonViewItem(null, [], null));
254
            }
255
        }
256
257
        foreach($lessons as $lessonNumber) {
258
            $hasLessonEntry = false;
259
            $lesson = $view->getLesson($lessonNumber);
260
261
            if($lesson !== null) {
262
                foreach ($lesson->getItems() as $item) {
263
                    if ($item instanceof TimetableLessonViewItem) {
264
                        $hasLessonEntry = true;
265
                        break;
266
                    }
267
                }
268
            } else {
269
                $hasLessonEntry = false;
270
            }
271
272
            if($hasLessonEntry === false) {
273
                $view->addItem($lessonNumber, new TimetableLessonViewItem(null, [], null));
274
            }
275
        }
276
    }
277
278
    /**
279
     * @param TimetableSupervision[] $supervisions
280
     */
281
    private function addSupervisions(iterable $supervisions, DashboardView $dashboardView): void {
282
        foreach($supervisions as $supervision) {
283
            if ($supervision->isBefore()) {
284
                $dashboardView->addItemBefore($supervision->getLesson(), new SupervisionViewItem($supervision));
285
            } else {
286
                $dashboardView->addItem($supervision->getLesson(), new SupervisionViewItem($supervision));
287
            }
288
        }
289
    }
290
291
    /**
292
     * @param Substitution[] $substitutions
293
     */
294
    private function addSubstitutions(iterable $substitutions, DashboardView $dashboardView, bool $computeAbsences): void {
295
        $freeTypes = $this->dashboardSettings->getFreeLessonSubstitutionTypes();
296
297
        foreach($substitutions as $substitution) {
298
            if($this->authorizationChecker->isGranted(SubstitutionVoter::View, $substitution) !== true) {
299
                continue;
300
            }
301
302
            $isFreeLesson = in_array($substitution->getType(), $freeTypes);
303
304
            if($substitution->startsBefore()) {
305
                $dashboardView->addItemBefore($substitution->getLessonStart(), new SubstitutionViewItem($substitution, $isFreeLesson, [ ], [ ], null, null));
306
307
                if($substitution->getLessonEnd() - $substitution->getLessonStart() === 0) {
308
                    // Do not expand more lessons when the end is the same lesson as the beginning
309
                    continue;
310
                }
311
            }
312
            $studyGroups = $substitution->getReplacementStudyGroups()->count() > 0 ? $substitution->getReplacementStudyGroups() : $substitution->getStudyGroups();
313
            $students = $this->getStudents($studyGroups);
314
315
            for ($lesson = $substitution->getLessonStart(); $lesson <= $substitution->getLessonEnd(); $lesson++) {
316
                $absentStudents = $computeAbsences ? $this->computeAbsentStudents($students, $lesson, $substitution->getDate()) : [ ];
317
                $timetableLesson = $this->findTimetableLesson($substitution, $lesson);
318
                $absenceLesson = null;
319
320
                if($timetableLesson !== null) {
321
                    $absenceLesson = $this->absenceLessonRepository->findOneForLesson($timetableLesson);
322
                }
323
324
                $dashboardView->addItem($lesson, new SubstitutionViewItem($substitution, $isFreeLesson, $students, $absentStudents, $timetableLesson, $absenceLesson));
325
            }
326
        }
327
    }
328
329
    private function findTimetableLesson(Substitution $substitution, int $lesson): ?TimetableLesson {
330
        $tuition = $this->tuitionRepository->findOneBySubstitution($substitution, $this->sectionResolver->getSectionForDate($substitution->getDate()));
0 ignored issues
show
Bug introduced by
It seems like $this->sectionResolver->...ubstitution->getDate()) can also be of type null; however, parameter $section of App\Repository\TuitionRe...findOneBySubstitution() does only seem to accept App\Entity\Section, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

330
        $tuition = $this->tuitionRepository->findOneBySubstitution($substitution, /** @scrutinizer ignore-type */ $this->sectionResolver->getSectionForDate($substitution->getDate()));
Loading history...
Bug introduced by
It seems like $substitution->getDate() can also be of type null; however, parameter $dateTime of App\Section\SectionResol...ce::getSectionForDate() does only seem to accept DateTime, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

330
        $tuition = $this->tuitionRepository->findOneBySubstitution($substitution, $this->sectionResolver->getSectionForDate(/** @scrutinizer ignore-type */ $substitution->getDate()));
Loading history...
331
332
        if($tuition === null) {
333
            return null;
334
        }
335
336
        $lessons = $this->timetableRepository->findAllByTuitions($substitution->getDate(), $substitution->getDate(), [ $tuition ]);
0 ignored issues
show
Bug introduced by
It seems like $substitution->getDate() can also be of type null; however, parameter $end of App\Repository\Timetable...ce::findAllByTuitions() does only seem to accept DateTime, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

336
        $lessons = $this->timetableRepository->findAllByTuitions($substitution->getDate(), /** @scrutinizer ignore-type */ $substitution->getDate(), [ $tuition ]);
Loading history...
Bug introduced by
It seems like $substitution->getDate() can also be of type null; however, parameter $start of App\Repository\Timetable...ce::findAllByTuitions() does only seem to accept DateTime, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

336
        $lessons = $this->timetableRepository->findAllByTuitions(/** @scrutinizer ignore-type */ $substitution->getDate(), $substitution->getDate(), [ $tuition ]);
Loading history...
337
338
        foreach($lessons as $timetableLesson) {
339
            if($timetableLesson->getLessonStart() <= $lesson && $lesson <= $timetableLesson->getLessonEnd()) {
340
                return $timetableLesson;
341
            }
342
        }
343
344
        return null;
345
    }
346
347
    /**
348
     * @param Message[] $messages
349
     */
350
    private function addMessages(iterable $messages, DashboardView $dashboardView): void {
351
        $this->sorter->sort($messages, MessageStrategy::class);
0 ignored issues
show
Bug introduced by
$messages of type iterable is incompatible with the type array expected by parameter $array of App\Sorting\Sorter::sort(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

351
        $this->sorter->sort(/** @scrutinizer ignore-type */ $messages, MessageStrategy::class);
Loading history...
352
353
        foreach($messages as $message) {
354
            if($this->authorizationChecker->isGranted(MessageVoter::View, $message) !== true) {
355
                continue;
356
            }
357
358
            $dashboardView->addMessage($message);
359
        }
360
    }
361
362
    /**
363
     * @param Exam[] $exams
364
     */
365
    private function addExams(iterable $exams, DashboardView $dashboardView, ?Teacher $teacher, bool $computeAbsences): void {
366
        foreach($exams as $exam) {
367
            if($this->authorizationChecker->isGranted(ExamVoter::Show, $exam) !== true) {
368
                continue;
369
            }
370
371
            /** @var int[] $tuitionTeacherIds */
372
            $tuitionTeacherIds = [ ];
373
374
            /** @var Tuition $tuition */
375
            foreach($exam->getTuitions() as $tuition) {
376
                $tuitionTeacherIds = array_merge($tuitionTeacherIds, array_map(fn(Teacher $teacher) => $teacher->getId(), $tuition->getTeachers()->toArray()));
377
            }
378
379
            $supervisions = [ ];
380
381
            if($teacher !== null) {
382
                /** @var ExamSupervision $supervision */
383
                foreach($exam->getSupervisions() as $supervision) {
384
                    $supervisions[$supervision->getLesson()] = $supervision->getTeacher()->getId();
385
                }
386
            }
387
388
            for($lesson = $exam->getLessonStart(); $lesson <= $exam->getLessonEnd(); $lesson++) {
389
                $absentStudents = $computeAbsences ? $this->computeAbsentStudents($exam->getStudents()->toArray(), $lesson, $exam->getDate(), [ ExamStudentsResolver::class ]) : [ ];
390
391
                if($teacher !== null) {
392
                    if(in_array($teacher->getId(), $tuitionTeacherIds)) {
393
                        $dashboardView->addItem($lesson, new ExamViewItem($exam, $absentStudents));
394
                    }
395
396
                    if(isset($supervisions[$lesson]) && $supervisions[$lesson] === $teacher->getId()) {
397
                        $dashboardView->addItem($lesson, new ExamSupervisionViewItem($exam, $absentStudents));
398
                    }
399
                } else {
400
                    $dashboardView->addItem($lesson, new ExamViewItem($exam, $absentStudents));
401
                }
402
            }
403
        }
404
    }
405
406
    private function addInfotexts(DateTime $dateTime, DashboardView $view): void {
407
        $infotexts = $this->infotextRepository->findAllByDate($dateTime);
408
409
        foreach($infotexts as $infotext) {
410
            $view->addInfotext($infotext);
411
        }
412
    }
413
414
    private function addAbsentTeachers(array $absences, DashboardView $view): void {
415
        $this->sorter->sort($absences, AbsentTeacherStrategy::class);
416
        foreach($absences as $absence) {
417
            if($this->authorizationChecker->isGranted(AbsenceVoter::View, $absence)) {
418
                $view->addAbsence($absence);
419
            }
420
        }
421
    }
422
423
    private function addAbsentStudyGroup(array $absences, DashboardView $view): void {
424
        $this->sorter->sort($absences, AbsentStudyGroupStrategy::class);
425
        foreach($absences as $absence) {
426
            if($this->authorizationChecker->isGranted(AbsenceVoter::View, $absence)) {
427
                $view->addAbsence($absence);
428
            }
429
        }
430
    }
431
432
    /**
433
     * @param Appointment[] $appointments
434
     */
435
    private function addAppointments(array $appointments, DashboardView $view): void {
436
        $freeCategories = $this->timetableSettings->getCategoryIds();
437
438
        foreach($appointments as $appointment) {
439
            if($this->authorizationChecker->isGranted(AppointmentVoter::View, $appointment)) {
440
                if(in_array($appointment->getCategory()->getId(), $freeCategories)) {
441
                    $view->removeLessons();;
442
                }
443
444
                $view->addAppointment($appointment);
445
            }
446
        }
447
    }
448
449
    /**
450
     * @param ResourceReservation[] $reservations
451
     */
452
    private function addRoomReservations(array $reservations, DashboardView $view): void {
453
        foreach($reservations as $reservation) {
454
            if($this->authorizationChecker->isGranted(ResourceReservationVoter::View)) {
455
                $violations = $this->validator->validate($reservation, null, ['collision']);
456
457
                for($lessonNumber = $reservation->getLessonStart(); $lessonNumber <= $reservation->getLessonEnd(); $lessonNumber++) {
458
                    $view->addItem($lessonNumber, new RoomReservationViewItem($reservation, $violations));
459
                }
460
            }
461
        }
462
    }
463
464
    /**
465
     * @param FreeTimespan[] $timespans
466
     */
467
    private function addFreeTimespans(array $timespans, DashboardView $view): void {
468
         foreach($timespans as $timespan) {
469
            for($lessonNumber = $timespan->getStart(); $lessonNumber <= $timespan->getEnd(); $lessonNumber++) {
470
                $view->addItem($lessonNumber, new FreeLessonView());
471
            }
472
        }
473
    }
474
475
    /**
476
     * @param Student[] $students
477
     * @param string[] $excludedResolvers FQCN of excluded strategies
478
     * @return AbsentStudentGroup[]
479
     */
480
    private function computeAbsentStudents(array $students, int $lesson, DateTime $dateTime, array $excludedResolvers = [ ]): array {
481
        $absentStudents = $this->absenceResolver->resolve($dateTime, $lesson, $students, $excludedResolvers);
482
483
        /** @var AbsentStudentGroup[] $groups */
484
        $groups = $this->grouper->group($absentStudents, AbstentStudentGroupStrategy::class);
485
        $this->sorter->sortGroupItems($groups, AbsentStudentStrategy::class);
486
487
        return $groups;
488
    }
489
490
    /**
491
     * @param iterable|StudyGroup[] $studyGroups
492
     * @return Student[]
493
     */
494
    private function getStudents(iterable $studyGroups): array {
495
        $students = [ ];
496
497
        foreach($studyGroups as $group) {
498
            /** @var StudyGroupMembership $membership */
499
            foreach($group->getMemberships() as $membership) {
500
                $students[] = $membership->getStudent();
501
            }
502
        }
503
504
        return $students;
505
    }
506
507
    /**
508
     * Filters the given substitutions for only those which are applied to the given grade.
509
     *
510
     * @param Substitution[] $substitutions
511
     * @return Substitution[]
512
     */
513
    private function filterSubstitutionsByGrade(array $substitutions, ?Grade $grade) {
514
        $result = [ ];
515
516
        foreach($substitutions as $substitution) {
517
            if($substitution->getReplacementGrades()->count() === 0 || $substitution->getReplacementGrades()->contains($grade)) {
518
                $result[] = $substitution;
519
            }
520
        }
521
522
        return $result;
523
    }
524
}