TimetableController::ics()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 7
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace App\Controller;
4
5
use App\Security\Voter\TimetableVoter;
6
use Symfony\Component\HttpFoundation\Response;
7
use App\Date\WeekOfYear;
8
use App\Entity\IcsAccessToken;
9
use App\Entity\IcsAccessTokenType;
10
use App\Entity\MessageScope;
11
use App\Entity\StudyGroupMembership;
12
use App\Entity\Subject;
13
use App\Entity\TimetableLesson;
14
use App\Entity\TimetableSupervision;
15
use App\Entity\User;
16
use App\Export\TimetableIcsExporter;
17
use App\Form\IcsAccessTokenType as DeviceTokenTypeForm;
18
use App\Grouping\Grouper;
19
use App\Message\DismissedMessagesHelper;
20
use App\Repository\ImportDateTypeRepositoryInterface;
21
use App\Repository\MessageRepositoryInterface;
22
use App\Repository\SubjectRepositoryInterface;
23
use App\Repository\TimetableLessonRepositoryInterface;
24
use App\Repository\TimetableSupervisionRepositoryInterface;
25
use App\Repository\UserRepositoryInterface;
26
use App\Security\IcsAccessToken\IcsAccessTokenManager;
27
use App\Settings\TimetableSettings;
28
use App\Sorting\Sorter;
29
use App\Timetable\TimetableFilter;
30
use App\Timetable\TimetableHelper;
31
use App\Utils\ArrayUtils;
32
use App\View\Filter\GradeFilter;
33
use App\View\Filter\RoomFilter;
34
use App\View\Filter\SectionFilter;
35
use App\View\Filter\StudentFilter;
36
use App\View\Filter\SubjectsFilter;
37
use App\View\Filter\TeachersFilter;
38
use DateTime;
39
use SchulIT\CommonBundle\Helper\DateHelper;
40
use SchulIT\CommonBundle\Utils\RefererHelper;
41
use Symfony\Component\HttpFoundation\Request;
42
use Symfony\Component\Routing\Annotation\Route;
43
44
#[Route(path: '/timetable')]
45
class TimetableController extends AbstractControllerWithMessages {
46
47
    private const OnlyOneWeek = 'timetable.only_one_week';
48
49
    use RequestTrait;
50
    use CalendarWeeksTrait;
0 ignored issues
show
Bug introduced by
The trait App\Controller\CalendarWeeksTrait requires the property $query which is not provided by App\Controller\TimetableController.
Loading history...
51
52
    public function __construct(MessageRepositoryInterface $messageRepository, DismissedMessagesHelper $dismissedMessagesHelper,
53
                                DateHelper $dateHelper, private TimetableHelper $timetableHelper, private TimetableSettings $timetableSettings,
54
                                RefererHelper $refererHelper) {
55
        parent::__construct($messageRepository, $dismissedMessagesHelper, $dateHelper, $refererHelper);
56
    }
57
58
    #[Route(path: '', name: 'timetable')]
59
    public function index(StudentFilter $studentFilter, TeachersFilter $teachersFilter, GradeFilter $gradeFilter, RoomFilter $roomFilter, SubjectsFilter $subjectFilter,
60
                          TimetableLessonRepositoryInterface $lessonRepository, TimetableSupervisionRepositoryInterface $supervisionRepository, TimetableFilter $timetableFilter, ImportDateTypeRepositoryInterface $importDateTypeRepository,
61
                          SubjectRepositoryInterface $subjectRepository, SectionFilter $sectionFilter, Request $request, UserRepositoryInterface $userRepository): Response {
62
        /** @var User $user */
63
        $user = $this->getUser();
64
65
        if($request->isMethod('POST')) {
66
            $onlyOneWeek = $request->request->getBoolean('only_one_week');
67
            $user->setData(self::OnlyOneWeek, $onlyOneWeek);
68
69
            $userRepository->persist($user);
70
            return $this->redirectToRoute('timetable', $request->query->all());
71
        }
72
73
        $sectionFilterView = $sectionFilter->handle($request->query->get('section', null));
74
        $gradeFilterView = $gradeFilter->handle($request->query->get('grade', null), $sectionFilterView->getCurrentSection(), $user);
75
        $roomFilterView = $roomFilter->handle($request->query->get('room', null), $user);
76
        $subjectFilterView = $subjectFilter->handle($this->getArrayOrNull($request->query->all('subjects')), $user);
77
        $studentFilterView = $studentFilter->handle($request->query->get('student', null), $sectionFilterView->getCurrentSection(), $user, $gradeFilterView->getCurrentGrade() === null && $roomFilterView->getCurrentRoom() === null && (is_countable($subjectFilterView->getCurrentSubjects()) ? count($subjectFilterView->getCurrentSubjects()) : 0) === 0);
78
        $teachersFilterView = $teachersFilter->handle($this->getArrayOrNull($request->query->all('teachers')), $sectionFilterView->getCurrentSection(), $user, $studentFilterView->getCurrentStudent() === null && $gradeFilterView->getCurrentGrade() === null && $roomFilterView->getCurrentRoom() === null && (is_countable($subjectFilterView->getCurrentSubjects()) ? count($subjectFilterView->getCurrentSubjects()) : 0) === 0);
79
80
        $selectedDate = $this->resolveSelectedDate($request, $sectionFilterView->getCurrentSection(), $this->dateHelper);
81
82
        $start = max(
83
            $selectedDate,
84
            $startDate = $this->timetableSettings->getStartDate($user->getUserType())
85
        );
86
        $end = min(
87
            (clone $start)->modify('+13 days'),
88
            $endDate = $this->timetableSettings->getEndDate($user->getUserType())
89
        );
90
91
        $lessons = [ ];
92
        $supervisions = [ ];
93
        $membershipsTypes = [ ];
94
95
        if($start <= $end) {
96
            if ($studentFilterView->getCurrentStudent() !== null) {
97
                $lessons = $lessonRepository->findAllByStudent($start, $end, $studentFilterView->getCurrentStudent());
98
                $lessons = $timetableFilter->filterStudentLessons($lessons);
99
100
                $gradeIdsWithMembershipTypes = $this->timetableSettings->getGradeIdsWithMembershipTypes();
101
102
                /** @var StudyGroupMembership $membership */
103
                foreach($studentFilterView->getCurrentStudent()->getStudyGroupMemberships() as $membership) {
104
                    foreach($membership->getStudyGroup()->getGrades() as $grade) {
105
                        if (in_array($grade->getId(), $gradeIdsWithMembershipTypes)) {
106
                            $membershipsTypes[$membership->getStudyGroup()->getId()] = $membership->getType();
107
                        }
108
                    }
109
                }
110
            } else if (count($teachersFilterView->getCurrentTeachers()) > 0) {
111
                $lessons = [ ];
112
                $supervisions = [ ];
113
114
                foreach($teachersFilterView->getCurrentTeachers() as $teacher) {
115
                    $lessons = array_merge($lessons, $timetableFilter->filterTeacherLessons($lessonRepository->findAllByTeacher($start, $end, $teacher)));
116
                    $supervisions = array_merge($supervisions, $supervisionRepository->findAllByTeacher($start, $end, $teacher));
117
                }
118
            } else if ($gradeFilterView->getCurrentGrade() !== null) {
119
                $lessons = $lessonRepository->findAllByGrade($start, $end, $gradeFilterView->getCurrentGrade());
120
                $lessons = $timetableFilter->filterGradeLessons($lessons);
121
            } else if ($roomFilterView->getCurrentRoom() !== null) {
122
                $lessons = $lessonRepository->findAllByRoom($start, $end, $roomFilterView->getCurrentRoom());
123
                $lessons = $timetableFilter->filterRoomLessons($lessons);
124
            } else if ((is_countable($subjectFilterView->getSubjects()) ? count($subjectFilterView->getSubjects()) : 0) > 0) {
125
                $lessons = $lessonRepository->findAllBySubjects($start, $end, $subjectFilterView->getCurrentSubjects());
126
                $lessons = $timetableFilter->filterSubjectsLessons($lessons);
127
            }
128
        }
129
130
        if((is_countable($lessons) ? count($lessons) : 0) === 0 && count($supervisions) === 0) {
131
            $timetable = null;
132
        } else {
133
            $weeks = $this->getWeeksToDisplay($start, $end, $user->getData(self::OnlyOneWeek, false));
134
            $timetable = $this->timetableHelper->makeTimetable($weeks, $lessons, $supervisions);
135
        }
136
137
        $startTimes = [ ];
138
        $endTimes = [ ];
139
140
        for($lesson = 1; $lesson <= $this->timetableSettings->getMaxLessons(); $lesson++) {
141
            $startTimes[$lesson] = $this->timetableSettings->getStart($lesson);
142
            $endTimes[$lesson] = $this->timetableSettings->getEnd($lesson);
143
        }
144
145
        $template = 'timetable/index.html.twig';
146
147
        if($request->query->getBoolean('print', false) === true) {
148
            $template = 'timetable/index_print.html.twig';
149
150
            if($timetable === null) {
151
                $query = $request->query->all();
152
                unset($query['print']);
153
                $this->addFlash('info', 'plans.timetable.print.empty');
154
                return $this->redirectToRoute('timetable', $query);
155
            }
156
        }
157
158
        $supervisionLabels = [ ];
159
        for($i = 1; $i <= $this->timetableSettings->getMaxLessons(); $i++) {
160
            $supervisionLabels[$i] = $this->timetableSettings->getDescriptionBeforeLesson($i);
161
        }
162
163
        $subjects = ArrayUtils::createArrayWithKeys(
164
            $subjectRepository->findAll(),
165
            fn(Subject $subject) => $subject->getAbbreviation()
166
        );
167
168
        $weekStarts = [ ];
169
170
        if($startDate !== null && $endDate !== null && $sectionFilterView->getCurrentSection() !== null) {
171
            $weekStarts = $this->listCalendarWeeks(
172
                max($startDate, $sectionFilterView->getCurrentSection()->getStart()),
173
                min($endDate, $sectionFilterView->getCurrentSection()->getEnd())
174
            );
175
        }
176
177
        return $this->renderWithMessages($template, [
178
            'compact' => count($teachersFilterView->getCurrentTeachers()) > 1,
179
            'timetable' => $timetable,
180
            'studentFilter' => $studentFilterView,
181
            'teachersFilter' => $teachersFilterView,
182
            'gradeFilter' => $gradeFilterView,
183
            'roomFilter'=> $roomFilterView,
184
            'subjectFilter' => $subjectFilterView,
185
            'sectionFilter' => $sectionFilterView,
186
            'startTimes' => $startTimes,
187
            'endTimes' => $endTimes,
188
            'gradesWithCourseNames' => $this->timetableSettings->getGradeIdsWithCourseNames(),
189
            'memberships' => $membershipsTypes,
190
            'query' => $request->query->all(),
191
            'supervisionLabels' => $supervisionLabels,
192
            'supervisionSubject' => $this->timetableSettings->getSupervisionLabel(),
193
            'supervisionColor' => $this->timetableSettings->getSupervisionColor(),
194
            'last_import_lessons' => $importDateTypeRepository->findOneByEntityClass(TimetableLesson::class),
195
            'last_import_supervisions' => $importDateTypeRepository->findOneByEntityClass(TimetableSupervision::class),
196
            'subjects' => $subjects,
197
            'selectedDate' => $selectedDate,
198
            'weekStarts' => $weekStarts,
199
            'onlyOneWeek' => $user->getData(self::OnlyOneWeek, false)
200
        ]);
201
    }
202
203
    /**
204
     * @param DateTime $start
205
     * @param DateTime $end
206
     * @param bool $onlyOneWeek
207
     * @return WeekOfYear[]
208
     */
209
    private function getWeeksToDisplay(DateTime $start, DateTime $end, bool $onlyOneWeek): array {
210
        $weeks = [
211
            (new WeekOfYear((int)$start->format('Y'), (int)$start->format('W'))),
212
            (new WeekOfYear((int)$end->format('Y'), (int)$end->format('W')))
213
        ];
214
215
        if($weeks[0]->getWeekNumber() === $weeks[1]->getWeekNumber() && $weeks[0]->getYear() === $weeks[1]->getYear()) {
216
            $weeks = [ $weeks[0] ];
217
        }
218
219
        if($onlyOneWeek === true) {
220
            $weeks = [ $weeks[0] ];
221
        }
222
223
        return $weeks;
224
    }
225
226
    #[Route(path: '/supervisions', name: 'timetable_supervisions')]
227
    public function supervisions(TimetableSupervisionRepositoryInterface $supervisionRepository, TimetableFilter $timetableFilter, ImportDateTypeRepositoryInterface $importDateTypeRepository,
0 ignored issues
show
Unused Code introduced by
The parameter $timetableFilter is not used and could be removed. ( Ignorable by Annotation )

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

227
    public function supervisions(TimetableSupervisionRepositoryInterface $supervisionRepository, /** @scrutinizer ignore-unused */ TimetableFilter $timetableFilter, ImportDateTypeRepositoryInterface $importDateTypeRepository,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
228
                                 SectionFilter $sectionFilter, Request $request, UserRepositoryInterface $userRepository) {
229
        $this->denyAccessUnlessGranted(TimetableVoter::Supervisions);
230
231
        /** @var User $user */
232
        $user = $this->getUser();
233
234
        if($request->isMethod('POST')) {
235
            $onlyOneWeek = $request->request->getBoolean('only_one_week');
236
            $user->setData(self::OnlyOneWeek, $onlyOneWeek);
237
238
            $userRepository->persist($user);
239
            return $this->redirectToRoute('timetable_supervisions', $request->query->all());
240
        }
241
242
        $sectionFilterView = $sectionFilter->handle($request->query->get('section', null));
243
        $selectedDate = $this->resolveSelectedDate($request, $sectionFilterView->getCurrentSection(), $this->dateHelper);
244
245
        $start = max(
246
            $selectedDate,
247
            $startDate = $this->timetableSettings->getStartDate($user->getUserType())
248
        );
249
        $end = min(
250
            (clone $start)->modify('+13 days'),
251
            $endDate = $this->timetableSettings->getEndDate($user->getUserType())
252
        );
253
254
        $timetable = null;
255
256
        if($start <= $end) {
257
            $supervisions = $supervisionRepository->findAllByRange($start, $end);
258
            $weeks = $this->getWeeksToDisplay($start, $end, $user->getData(self::OnlyOneWeek, false));
259
260
            if(count($supervisions) > 0) {
261
                $timetable = $this->timetableHelper->makeTimetable($weeks, [], $supervisions);
262
            }
263
        }
264
265
        $startTimes = [ ];
266
        $endTimes = [ ];
267
268
        for($lesson = 1; $lesson <= $this->timetableSettings->getMaxLessons(); $lesson++) {
269
            $startTimes[$lesson] = $this->timetableSettings->getStart($lesson);
270
            $endTimes[$lesson] = $this->timetableSettings->getEnd($lesson);
271
        }
272
273
        $template = 'timetable/index.html.twig';
0 ignored issues
show
Unused Code introduced by
The assignment to $template is dead and can be removed.
Loading history...
274
275
        if($request->query->getBoolean('print', false) === true) {
276
            $template = 'timetable/index_print.html.twig';
277
278
            if($timetable === null) {
279
                $query = $request->query->all();
280
                unset($query['print']);
281
                $this->addFlash('info', 'plans.timetable.print.empty');
282
                return $this->redirectToRoute('timetable', $query);
283
            }
284
        }
285
286
        $supervisionLabels = [ ];
287
        for($i = 1; $i <= $this->timetableSettings->getMaxLessons(); $i++) {
288
            $supervisionLabels[$i] = $this->timetableSettings->getDescriptionBeforeLesson($i);
289
        }
290
291
        $weekStarts = [ ];
292
293
        if($startDate !== null && $endDate !== null && $sectionFilterView->getCurrentSection() !== null) {
294
            $weekStarts = $this->listCalendarWeeks(
295
                max($startDate, $sectionFilterView->getCurrentSection()->getStart()),
296
                min($endDate, $sectionFilterView->getCurrentSection()->getEnd())
297
            );
298
        }
299
300
        return $this->renderWithMessages('timetable/supervisions.html.twig', [
301
            'timetable' => $timetable,
302
            'sectionFilter' => $sectionFilterView,
303
            'startTimes' => $startTimes,
304
            'endTimes' => $endTimes,
305
            'query' => $request->query->all(),
306
            'supervisionLabels' => $supervisionLabels,
307
            'supervisionSubject' => $this->timetableSettings->getSupervisionLabel(),
308
            'supervisionColor' => $this->timetableSettings->getSupervisionColor(),
309
            'last_import_lessons' => $importDateTypeRepository->findOneByEntityClass(TimetableLesson::class),
310
            'last_import_supervisions' => $importDateTypeRepository->findOneByEntityClass(TimetableSupervision::class),
311
            'selectedDate' => $selectedDate,
312
            'weekStarts' => $weekStarts,
313
            'onlyOneWeek' => $user->getData(self::OnlyOneWeek, false)
314
        ]);
315
316
    }
317
318
    #[Route(path: '/export', name: 'timetable_export')]
319
    public function export(Request $request, IcsAccessTokenManager $manager): Response {
320
        /** @var User $user */
321
        $user = $this->getUser();
322
323
        $deviceToken = (new IcsAccessToken())
324
            ->setType(IcsAccessTokenType::Timetable)
325
            ->setUser($user);
326
327
        $form = $this->createForm(DeviceTokenTypeForm::class, $deviceToken);
328
        $form->handleRequest($request);
329
330
        if($form->isSubmitted() && $form->isValid()) {
331
            $deviceToken = $manager->persistToken($deviceToken);
332
        }
333
334
        return $this->renderWithMessages('timetable/export.html.twig', [
335
            'form' => $form->createView(),
336
            'token' => $deviceToken
337
        ]);
338
    }
339
340
    #[Route(path: '/ics/download', name: 'timetable_ics')]
341
    #[Route(path: '/ics/downloads/{token}', name: 'timetable_ics_token')]
342
    public function ics(TimetableIcsExporter $icsExporter): Response {
343
        /** @var User $user */
344
        $user = $this->getUser();
345
346
        return $icsExporter->getIcsResponse($user);
347
    }
348
349
    protected function getMessageScope(): MessageScope {
350
        return MessageScope::Timetable;
351
    }
352
}