DashboardController::dashboard()   F
last analyzed

Complexity

Conditions 23
Paths 2401

Size

Total Lines 114
Code Lines 74

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 552

Importance

Changes 0
Metric Value
cc 23
eloc 74
c 0
b 0
f 0
nc 2401
nop 14
dl 0
loc 114
rs 0
ccs 0
cts 66
cp 0
crap 552

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace App\Controller;
4
5
use App\Repository\NotificationRepositoryInterface;
6
use Symfony\Component\HttpFoundation\Response;
7
use App\Dashboard\DashboardViewHelper;
8
use App\Dashboard\DashboardViewCollapseHelper;
9
use App\Entity\Section;
10
use App\Entity\Substitution;
11
use App\Entity\User;
12
use App\Entity\UserType;
13
use App\Repository\ImportDateTypeRepositoryInterface;
14
use App\Repository\MessageRepositoryInterface;
15
use App\Repository\SectionRepositoryInterface;
16
use App\Repository\UserRepositoryInterface;
17
use App\Settings\DashboardSettings;
18
use App\Settings\SubstitutionSettings;
19
use App\Settings\TimetableSettings;
20
use App\Utils\EnumArrayUtils;
0 ignored issues
show
Bug introduced by
The type App\Utils\EnumArrayUtils was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use App\View\Filter\RoomFilter;
22
use App\View\Filter\StudentFilter;
23
use App\View\Filter\TeacherFilter;
24
use App\View\Filter\UserTypeFilter;
25
use DateTime;
26
use League\Csv\Exception;
27
use SchulIT\CommonBundle\Helper\DateHelper;
28
use Symfony\Component\HttpFoundation\Request;
29
use Symfony\Component\Routing\Annotation\Route;
30
31
class DashboardController extends AbstractController {
32
33
    use DateTimeHelperTrait;
34
35
    private const ShowTimesKey = 'dashboard.show_times';
36
    private const IncludeGradeMessagesKey = 'dashboard.include_grade_messages';
37
38
    #[Route(path: '/', name: 'index')]
39
    public function index(): Response {
40
        return $this->redirectToRoute('dashboard');
41
    }
42
43
    #[Route(path: '/dashboard', name: 'dashboard')]
44
    public function dashboard(StudentFilter $studentFilter, TeacherFilter $teacherFilter, UserTypeFilter $userTypeFilter, RoomFilter $roomFilter,
45
                              DashboardViewHelper $dashboardViewHelper, DashboardViewCollapseHelper $dashboardViewMergeHelper,
46
                              DateHelper $dateHelper, DashboardSettings $settings, TimetableSettings $timetableSettings, SectionRepositoryInterface $sectionRepository,
47
                              UserRepositoryInterface $userRepository, ImportDateTypeRepositoryInterface $importDateTypeRepository,
48
                              NotificationRepositoryInterface $notificationRepository, Request $request): Response {
49
        /** @var User $user */
50
        $user = $this->getUser();
51
52
        if($request->isMethod('POST')) {
53
            $showTimes = $request->request->getBoolean('show_times', false);
54
            $user->setData(self::ShowTimesKey, $showTimes);
55
56
            $includeGradeMessages = $request->request->getBoolean('include_grade_messages', false);
57
            $user->setData(self::IncludeGradeMessagesKey, $includeGradeMessages);
58
59
            $userRepository->persist($user);
60
61
            return $this->redirectToRoute('dashboard', $request->query->all());
62
        }
63
64
        $selectedDate = null;
65
        try {
66
            if($request->query->has('date')) {
67
                $selectedDate = new DateTime($request->query->get('date', null));
68
                $selectedDate->setTime(0, 0, 0);
69
            }
70
        } catch (\Exception) {
71
            $selectedDate = null;
72
        }
73
74
        if($selectedDate === null) {
75
            $selectedDate = $this->getTodayOrNextDay($dateHelper, $settings->getNextDayThresholdTime());
76
77
            while($settings->skipWeekends() && $selectedDate->format('N') > 5) {
78
                $selectedDate->modify('+1 day');
79
            }
80
        }
81
82
        $dateHasSection = true;
83
        $section = $this->getSectionForDate($selectedDate, $sectionRepository, $dateHasSection);
84
85
        $days = $this->getListOfSurroundingDays($selectedDate, $settings->getNumberFutureDays(), $settings->getNumberPastDays(), $settings->skipWeekends());
86
87
        $roomFilterView = $roomFilter->handle($request->query->get('room', null), $user);
88
        $studentFilterView = $studentFilter->handle($request->query->get('student', null), $section, $user);
89
        $teacherFilterView = $teacherFilter->handle($request->query->get('teacher', null), $section, $user, $studentFilterView->getCurrentStudent() === null && $roomFilterView->getCurrentRoom() === null);
90
        $userTypeFilterView = $userTypeFilter->handle($request->query->get('user_type', null), $user, $user->isStudentOrParent(), UserType::Student, [ UserType::Student, UserType::Parent ]);
91
92
        $includeGradeMessages = $user->getData(self::IncludeGradeMessagesKey, false);
93
94
        if($studentFilterView->getCurrentStudent() !== null) {
95
            if($userTypeFilterView->getCurrentType() === null) {
96
                $userTypeFilterView->setCurrentType(UserType::Student);
97
            }
98
            $view = $dashboardViewHelper->createViewForStudentOrParent($studentFilterView->getCurrentStudent(), $selectedDate, $userTypeFilterView->getCurrentType());
99
        } else if($teacherFilterView->getCurrentTeacher() !== null) {
100
            if($user->getTeacher() === null || $user->getTeacher()->getId() !== $teacherFilterView->getCurrentTeacher()->getId()) {
101
                // Only include grade messages if the current user is the selected user in the teacher filter.
102
                $includeGradeMessages = false;
103
            }
104
105
            $view = $dashboardViewHelper->createViewForTeacher($teacherFilterView->getCurrentTeacher(), $selectedDate, $includeGradeMessages);
106
        } else if($roomFilterView->getCurrentRoom() !== null) {
107
            $view = $dashboardViewHelper->createViewForRoom($roomFilterView->getCurrentRoom(), $selectedDate);
108
        } else {
109
            $view = $dashboardViewHelper->createViewForUser($user, $selectedDate);
110
        }
111
112
        $startTimes = [ ];
113
        $endTimes = [ ];
114
115
        $showTimes = $user->getData(self::ShowTimesKey, true) === true;
116
117
        for ($lesson = 1; $lesson <= $timetableSettings->getMaxLessons(); $lesson++) {
118
            $startTimes[$lesson] = $showTimes ? $timetableSettings->getStart($lesson) : null;
119
            $endTimes[$lesson] = $showTimes ? $timetableSettings->getEnd($lesson) : null;
120
        }
121
122
        if($view !== null) {
123
            $dashboardViewMergeHelper->collapseView($view, $teacherFilterView->getCurrentTeacher());
124
        }
125
126
        $supervisionLabels = [ ];
127
        for($i = 1; $i <= $timetableSettings->getMaxLessons(); $i++) {
128
            $supervisionLabels[$i] = $timetableSettings->getDescriptionBeforeLesson($i);
129
        }
130
131
        $template = 'dashboard/one_column.html.twig';
132
133
        if(count($view->getLessons()) > 0 && (count($view->getAppointments()) > 0 || count($view->getMessages()) > 0 || count($view->getPriorityMessages()) > 0)) {
134
            $template = 'dashboard/two_columns.html.twig';
135
        }
136
137
        return $this->render($template, [
138
            'studentFilter' => $studentFilterView,
139
            'teacherFilter' => $teacherFilterView,
140
            'userTypeFilter' => $userTypeFilterView,
141
            'roomFilter' => $roomFilterView,
142
            'view' => $view,
143
            'days' => $days,
144
            'selectedDate' => $selectedDate,
145
            'startTimes' => $startTimes,
146
            'endTimes' => $endTimes,
147
            'gradesWithCourseNames' => $timetableSettings->getGradeIdsWithCourseNames(),
148
            'supervisionLabels' => $supervisionLabels,
149
            'showTimes' => $showTimes,
150
            'includeGradeMessages' => $user->getData(self::IncludeGradeMessagesKey, false),
151
            'canIncludeGradeMessages' => $user->getTeacher() !== null,
152
            'last_import' => $importDateTypeRepository->findOneByEntityClass(Substitution::class),
153
            'settings' => $settings,
154
            'section' => $section,
155
            'dateHasSection' => $dateHasSection,
156
            'unreadNotificationsCount' => $notificationRepository->countUnreadForUser($user)
157
        ]);
158
    }
159
160
    private function getSectionForDate(DateTime $dateTime, SectionRepositoryInterface $sectionRepository, bool &$dateHasSection): ?Section {
161
        $dateHasSection = true;
162
        $section = $sectionRepository->findOneByDate($dateTime);
163
164
        if($section === null) {
165
            $dateHasSection = false;
166
            $sections = $sectionRepository->findAll();
167
168
            if(count($sections) === 0) {
169
                return null;
170
            }
171
172
            $nearestSection = $sections[0];
173
            $min = $dateTime->diff($sections[0]->getStart())->format('%a');
174
175
            foreach($sections as $section) {
176
                $diff = $dateTime->diff($section->getStart())->format('%a');
177
178
                if($diff < $min) {
179
                    $min = $diff;
180
                    $nearestSection = $section;
181
                }
182
            }
183
184
            return $nearestSection;
185
        }
186
187
        return $section;
188
    }
189
190
    /**
191
     * @return \DateTime[]
192
     */
193
    private function getListOfSurroundingDays(DateTime $dateTime, int $daysInFuture, int $daysInPast, bool $skipWeekends): array {
194
        $days = [ ];
195
196
        for($i = $daysInPast; $i > 0; $i--) {
197
            $day = (clone $dateTime)->modify(sprintf('-%d days', $i));
198
199
            if($skipWeekends === false || $day->format('N') < 6) {
200
                $days[] = $day;
201
            }
202
        }
203
204
        $days[] = $dateTime;
205
206
        for($i = 1; $i <= $daysInFuture; $i++) {
207
            $day = (clone $dateTime)->modify(sprintf('+%d days', $i));
208
209
            if($skipWeekends === false || $day->format('N') < 6) {
210
                $days[] = $day;
211
            }
212
        }
213
214
        return $days;
215
    }
216
}