Passed
Push — master ( 4959cd...65a92c )
by Marcel
17:47
created

ExamIcsExporter::makeIcsItems()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 11
c 0
b 0
f 0
nc 5
nop 2
dl 0
loc 23
ccs 0
cts 9
cp 0
crap 42
rs 9.2222
1
<?php
2
3
namespace App\Export;
4
5
use App\Entity\Exam;
6
use App\Entity\ExamSupervision;
7
use App\Entity\Grade;
8
use App\Entity\Teacher;
9
use App\Entity\Tuition;
10
use App\Entity\User;
11
use App\Ics\IcsHelper;
12
use App\Repository\ExamRepositoryInterface;
13
use App\Security\Voter\ExamVoter;
14
use App\Settings\ExamSettings;
15
use App\Timetable\TimetableTimeHelper;
16
use DateTime;
17
use Jsvrcek\ICS\Model\CalendarEvent;
18
use Jsvrcek\ICS\Model\Description\Location;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
21
use Symfony\Contracts\Translation\TranslatorInterface;
22
23
class ExamIcsExporter {
24
    public function __construct(private ExamSettings $examSettings, private ExamRepositoryInterface $examRepository, private TimetableTimeHelper $timetableTimeHelper, private IcsHelper $icsHelper, private TranslatorInterface $translator, private AuthorizationCheckerInterface $authorizationChecker)
25
    {
26
    }
27
28
    public function getIcsResponse(User $user): Response {
29
        return $this->icsHelper->getIcsResponse(
30
            $this->translator->trans('exams.export.title'),
31
            $this->translator->trans('exams.export.description', [ '%user%' => $user->getUsername() ]),
32
            $this->getIcsItems($user),
33
            $this->translator->trans('plans.exams.export.download.filename')
34
        );
35
    }
36
37
    /**
38
     * @return CalendarEvent[]
39
     */
40
    private function getIcsItems(User $user) {
41
        if($this->examSettings->isVisibileFor($user->getUserType()) === false) {
42
            return [ ];
43
        }
44
45
        $exams = [ ];
46
47
        if($user->isStudentOrParent()) {
48
            $exams = $this->examRepository->findAllByStudents($user->getStudents()->toArray(), null, false, true);
49
        } else if($user->isTeacher()) {
50
            $exams = $this->examRepository->findAllByTeacher($user->getTeacher(), null, false, true);
0 ignored issues
show
Bug introduced by
It seems like $user->getTeacher() can also be of type null; however, parameter $teacher of App\Repository\ExamRepos...ace::findAllByTeacher() does only seem to accept App\Entity\Teacher, 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

50
            $exams = $this->examRepository->findAllByTeacher(/** @scrutinizer ignore-type */ $user->getTeacher(), null, false, true);
Loading history...
51
        }
52
53
        $exams = array_filter($exams, fn(Exam $exam) => $this->authorizationChecker->isGranted(ExamVoter::Show, $exam));
54
55
        $items = [ ];
56
57
        foreach($exams as $exam) {
58
            $items = array_merge($items, $this->makeIcsItems($exam, $user));
59
        }
60
61
        return $items;
62
    }
63
64
    /**
65
     * @return CalendarEvent[]
66
     */
67
    private function makeIcsItems(Exam $exam, User $user) {
68
        if($user->isStudentOrParent()) {
69
            return [ $this->makeIcsItem($exam) ];
70
        }
71
72
        $items = [ ];
73
74
        if($this->isExamTeacher($exam, $user->getTeacher())) {
75
            $items[] = $this->makeIcsItem($exam);
76
        }
77
78
        if($user->getTeacher() !== null) {
79
            /** @var ExamSupervision[] $supervisions */
80
            $supervisions = $exam->getSupervisions();
81
82
            foreach($supervisions as $supervision) {
83
                if($supervision->getTeacher()->getId() === $user->getTeacher()->getId()) {
84
                    $items[] = $this->makeIcsItemSupervision($exam,$exam->getLessonStart() + $supervision->getLesson() - 1);
85
                }
86
            }
87
        }
88
89
        return $items;
90
    }
91
92
    private function makeIcsItem(Exam $exam): CalendarEvent {
93
        $start = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonStartDateTime($exam->getDate(), $exam->getLessonStart()));
0 ignored issues
show
Bug introduced by
It seems like $exam->getDate() can also be of type null; however, parameter $date of App\Timetable\TimetableT...etLessonStartDateTime() 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

93
        $start = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonStartDateTime(/** @scrutinizer ignore-type */ $exam->getDate(), $exam->getLessonStart()));
Loading history...
Bug introduced by
It seems like $exam->getDate() can also be of type null; however, parameter $day of App\Export\ExamIcsExporter::getDateTime() 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

93
        $start = $this->getDateTime(/** @scrutinizer ignore-type */ $exam->getDate(), $this->timetableTimeHelper->getLessonStartDateTime($exam->getDate(), $exam->getLessonStart()));
Loading history...
94
        $end = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonEndDateTime($exam->getDate(), $exam->getLessonEnd()));
0 ignored issues
show
Bug introduced by
It seems like $exam->getDate() can also be of type null; however, parameter $date of App\Timetable\TimetableT...:getLessonEndDateTime() 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

94
        $end = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonEndDateTime(/** @scrutinizer ignore-type */ $exam->getDate(), $exam->getLessonEnd()));
Loading history...
95
        $description = $this->translator->trans('exams.export.exam_description', [
96
            '%tuitions%' => $this->getTuitionsAsString($exam->getTuitions()->toArray())
97
        ]);
98
99
        $event = (new CalendarEvent())
100
            ->setUid(sprintf('exam-%d', $exam->getId()))
101
            ->setSummary($description)
102
            ->setDescription($description)
103
            ->setStart($start)
104
            ->setEnd($end);
105
106
        if($exam->getRoom() !== null) {
107
            $event->setLocations([
108
                (new Location())
109
                    ->setName($exam->getRoom()->getName())
110
            ]);
111
        }
112
113
        return $event;
114
    }
115
116
    private function makeIcsItemSupervision(Exam $exam, int $lesson): CalendarEvent {
117
        $start = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonStartDateTime($exam->getDate(), $lesson));
0 ignored issues
show
Bug introduced by
It seems like $exam->getDate() can also be of type null; however, parameter $day of App\Export\ExamIcsExporter::getDateTime() 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

117
        $start = $this->getDateTime(/** @scrutinizer ignore-type */ $exam->getDate(), $this->timetableTimeHelper->getLessonStartDateTime($exam->getDate(), $lesson));
Loading history...
Bug introduced by
It seems like $exam->getDate() can also be of type null; however, parameter $date of App\Timetable\TimetableT...etLessonStartDateTime() 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

117
        $start = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonStartDateTime(/** @scrutinizer ignore-type */ $exam->getDate(), $lesson));
Loading history...
118
        $end = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonEndDateTime($exam->getDate(), $lesson));
0 ignored issues
show
Bug introduced by
It seems like $exam->getDate() can also be of type null; however, parameter $date of App\Timetable\TimetableT...:getLessonEndDateTime() 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

118
        $end = $this->getDateTime($exam->getDate(), $this->timetableTimeHelper->getLessonEndDateTime(/** @scrutinizer ignore-type */ $exam->getDate(), $lesson));
Loading history...
119
        $description = $this->translator->trans('exams.export.supervision_description', [
120
            '%tuitions%' => $this->getTuitionsAsString($exam->getTuitions()->toArray())
121
        ]);
122
123
        $event = (new CalendarEvent())
124
            ->setUid(sprintf('exam-%d-supervision-%d', $exam->getId(), $lesson))
125
            ->setSummary($description)
126
            ->setDescription($description)
127
            ->setStart($start)
128
            ->setEnd($end);
129
130
131
        if($exam->getRoom() !== null) {
132
            $event->setLocations([
133
                (new Location())
134
                    ->setName($exam->getRoom()->getName())
135
            ]);
136
        }
137
138
        return $event;
139
    }
140
141
    private function isExamTeacher(Exam $exam, ?Teacher $teacher): bool {
142
        if($teacher === null) {
143
            return false;
144
        }
145
146
        /** @var Tuition $tuition */
147
        foreach($exam->getTuitions() as $tuition) {
148
            foreach($tuition->getTeachers() as $currentTeacher) {
149
                if($currentTeacher->getId() === $teacher->getId()) {
150
                    return true;
151
                }
152
            }
153
        }
154
155
        return false;
156
    }
157
158
    /**
159
     * @param Tuition[] $tuitions
160
     */
161
    private function getTuitionsAsString($tuitions): string {
162
        $strings = [ ];
163
164
        foreach($tuitions as $tuition) {
165
            $grades = [ ];
166
167
            foreach($tuition->getStudyGroup()->getGrades() as $grade) {
168
                $grades[$grade->getId()] = $grade;
169
            }
170
171
            $strings[] = $this->translator->trans('exams.export.tuition', [
172
                '%name%' => $tuition->getName(),
173
                '%grades%' => $this->getGradesAsString($grades)
174
            ]);
175
        }
176
177
        return implode(',', $strings);
178
    }
179
180
    /**
181
     * @param Grade[] $grades
182
     */
183
    private function getGradesAsString($grades): string {
184
        return implode(', ', array_map(fn(Grade $grade) => $grade->getName(), $grades));
185
    }
186
187
    private function getDateTime(DateTime $day, DateTime $time) {
188
        $dateString = sprintf('%s %s:00', $day->format('Y-m-d'), $time->format('H:i'));
189
        return new DateTime($dateString);
190
    }
191
}