EntryOverviewHelper::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 13
dl 0
loc 2
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

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\Book;
4
5
use App\Entity\BookComment;
6
use App\Entity\Grade;
7
use App\Entity\LessonEntry;
8
use App\Entity\Substitution;
9
use App\Entity\Teacher;
10
use App\Entity\TimetableLesson;
11
use App\Entity\Tuition;
12
use App\Grouping\Grouper;
13
use App\Grouping\LessonDayStrategy;
14
use App\Repository\AppointmentCategoryRepositoryInterface;
15
use App\Repository\AppointmentRepositoryInterface;
16
use App\Repository\BookCommentRepositoryInterface;
17
use App\Repository\FreeTimespanRepositoryInterface;
18
use App\Repository\LessonAttendanceRepositoryInterface;
19
use App\Repository\LessonEntryRepositoryInterface;
20
use App\Repository\SubstitutionRepositoryInterface;
21
use App\Repository\TimetableLessonRepositoryInterface;
22
use App\Repository\TuitionRepositoryInterface;
23
use App\Section\SectionResolverInterface;
24
use App\Settings\TimetableSettings;
25
use App\Sorting\LessonDayGroupStrategy;
26
use App\Sorting\LessonStrategy;
27
use App\Sorting\Sorter;
28
use App\Utils\ArrayUtils;
29
use DateTime;
30
31
class EntryOverviewHelper {
32
    public function __construct(private TimetableLessonRepositoryInterface $lessonRepository, private TuitionRepositoryInterface $tuitionRepository, private LessonEntryRepositoryInterface $entryRepository, private BookCommentRepositoryInterface $commentRepository, private LessonAttendanceRepositoryInterface $attendanceRepository, private SectionResolverInterface $sectionResolver, private TimetableSettings $timetableSettings, private AppointmentCategoryRepositoryInterface $appointmentCategoryRepository, private AppointmentRepositoryInterface $appointmentRepository, private FreeTimespanRepositoryInterface $freeTimespanRepository, private SubstitutionRepositoryInterface $substitutionRepository, private Grouper $grouper, private Sorter $sorter)
33
    {
34
    }
35
36
    public function computeOverviewForTuition(Tuition $tuition, DateTime $start, DateTime $end): EntryOverview {
37
        $entries = $this->entryRepository->findAllByTuition($tuition, $start, $end);
38
        $comments = $this->commentRepository->findAllByDateAndTuition($tuition, $start, $end);
39
40
        return $this->computeOverview([$tuition], $entries, $comments, [ ], $start, $end);
41
    }
42
43
    /**
44
     * @param Tuition[] $tuitions
45
     * @param LessonEntry[] $entries
46
     * @param BookComment[] $comments
47
     * @param Substitution[] $substitutions
48
     */
49
    private function computeOverview(array $tuitions, array $entries, array $comments, array $substitutions, DateTime $start, DateTime $end): EntryOverview {
50
        if($start > $end) {
51
            $tmp = $start;
52
            $start = $end;
53
            $end = $tmp;
54
        }
55
56
        $tuitions = array_filter($tuitions, fn(Tuition $tuition) => $tuition->isBookEnabled());
57
58
        $lessons = [ ];
59
60
        foreach($entries as $entry) {
61
            if($entry->getTuition() === null) {
62
                // discard entries without tuition
63
                continue;
64
            }
65
66
            $presentCount = $this->attendanceRepository->countPresent($entry);
67
            $absentCount = $this->attendanceRepository->countAbsent($entry);
68
            $lateCount = $this->attendanceRepository->countLate($entry);
69
70
            for($lessonNumber = $entry->getLessonStart(); $lessonNumber <= $entry->getLessonEnd(); $lessonNumber++) {
71
                $key = sprintf('%s-%d-%s', $entry->getLesson()->getDate()->format('Y-m-d'), $lessonNumber, $entry->getTuition()->getUuid()->toString());
72
73
                $lesson = new Lesson(clone $entry->getLesson()->getDate(), $lessonNumber, null, $entry);
74
                $lesson->setAbsentCount($absentCount);
75
                $lesson->setPresentCount($presentCount);
76
                $lesson->setLateCount($lateCount);
77
78
                $lessons[$key] = $lesson;
79
            }
80
        }
81
82
        $weekNumbers = [ ];
83
        $currentWeek = clone $start;
84
        while($currentWeek < $end) {
85
            $weekNumber = (int)$currentWeek->format('W');
86
87
            if(!in_array($weekNumber, $weekNumbers)) {
88
                $weekNumbers[] = $weekNumber;
89
            }
90
91
            $currentWeek = $currentWeek->modify('+7 days');
92
        }
93
94
        $timetableLessons = $this->lessonRepository->findAllByTuitions($start, $end, $tuitions);
95
96
        $current = clone $start;
97
        while($current <= $end) {
98
            $dailyLessons = array_filter($timetableLessons, fn(TimetableLesson $lesson) => $lesson->getDate() == $current);
99
100
            foreach($dailyLessons as $dailyLesson) {
101
                for($lessonNumber = $dailyLesson->getLessonStart(); $lessonNumber <= $dailyLesson->getLessonEnd(); $lessonNumber++) {
102
                    $key = sprintf('%s-%d-%s', $current->format('Y-m-d'), $lessonNumber, $dailyLesson->getTuition()->getUuid()->toString());
103
104
                    if (!array_key_exists($key, $lessons)) {
105
                        $lessons[$key] = new Lesson(clone $current, $lessonNumber);
106
                    }
107
108
                    $lessons[$key]->setLesson($dailyLesson);
109
                }
110
            }
111
112
            $current = $current->modify('+1 day');
113
        }
114
115
        foreach($substitutions as $substitution) {
116
            $tuition = $this->tuitionRepository->findOneBySubstitution($substitution, $this->sectionResolver->getSectionForDate($substitution->getDate()));
0 ignored issues
show
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

116
            $tuition = $this->tuitionRepository->findOneBySubstitution($substitution, $this->sectionResolver->getSectionForDate(/** @scrutinizer ignore-type */ $substitution->getDate()));
Loading history...
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

116
            $tuition = $this->tuitionRepository->findOneBySubstitution($substitution, /** @scrutinizer ignore-type */ $this->sectionResolver->getSectionForDate($substitution->getDate()));
Loading history...
117
118
            if($tuition === null) {
119
                continue;
120
            }
121
122
            $timetableLessons = $this->lessonRepository->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

122
            $timetableLessons = $this->lessonRepository->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

122
            $timetableLessons = $this->lessonRepository->findAllByTuitions(/** @scrutinizer ignore-type */ $substitution->getDate(), $substitution->getDate(), [$tuition]);
Loading history...
123
124
            // Filter correct lesson
125
            foreach($timetableLessons as $dailyLesson) {
126
                for($lessonNumber = $dailyLesson->getLessonStart(); $lessonNumber <= $dailyLesson->getLessonEnd(); $lessonNumber++) {
127
                    if($substitution->getLessonStart() <= $lessonNumber && $lessonNumber <= $substitution->getLessonEnd()) {
128
                        $key = sprintf('%s-%d-%s', $substitution->getDate()->format('Y-m-d'), $lessonNumber, $dailyLesson->getTuition()->getUuid()->toString());
129
130
                        if (!array_key_exists($key, $lessons)) {
131
                            $lessons[$key] = new Lesson($substitution->getDate(), $lessonNumber, $dailyLesson, null, $substitution);
0 ignored issues
show
Bug introduced by
It seems like $substitution->getDate() can also be of type null; however, parameter $date of App\Book\Lesson::__construct() 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

131
                            $lessons[$key] = new Lesson(/** @scrutinizer ignore-type */ $substitution->getDate(), $lessonNumber, $dailyLesson, null, $substitution);
Loading history...
132
                        }
133
134
                        // Set correct entry
135
                        /** @var LessonEntry $lessonEntry */
136
                        foreach($dailyLesson->getEntries() as $lessonEntry) {
137
                            if($lessonEntry->getLessonStart() <= $lessonNumber && $lessonNumber <= $lessonEntry->getLessonEnd()) {
138
                                $lessons[$key]->setEntry($lessonEntry);
139
                                break;
140
                            }
141
                        }
142
143
                        if($lessons[$key]->getLesson() === null) {
144
                            $lessons[$key]->setLesson($dailyLesson);
145
                        }
146
                    }
147
                }
148
            }
149
        }
150
151
        $groups = $this->grouper->group(array_values($lessons), LessonDayStrategy::class);
152
        $this->sorter->sort($groups, LessonDayGroupStrategy::class);
153
        $this->sorter->sortGroupItems($groups, LessonStrategy::class);
154
155
        $freeTimespans = $this->computeFreeTimespans($start, $end);
156
157
        return new EntryOverview($start, $end, $groups, $comments, $freeTimespans);
158
    }
159
160
    public function computeOverviewForTeacher(Teacher $teacher, DateTime $start, DateTime $end): EntryOverview {
161
        $section = $this->sectionResolver->getSectionForDate($start);
162
        $entries = [ ];
163
        $tuitions = [ ];
164
        $comments = [ ];
165
166
        if($section !== null) {
167
            $entries = $this->entryRepository->findAllBySubstituteTeacher($teacher, $start, $end);
168
            $tuitions = $this->tuitionRepository->findAllByTeacher($teacher, $section);
169
170
            foreach($tuitions as $tuition) {
171
                $entries = array_merge($entries, $this->entryRepository->findAllByTuition($tuition, $start, $end));
172
                $comments = array_merge($comments, $this->commentRepository->findAllByDateAndTuition($tuition, $start, $end));
173
            }
174
175
            $comments = ArrayUtils::unique($comments);
176
        }
177
178
        $substitutions = [ ];
179
180
        $current = clone $start;
181
        while($current <= $end) {
182
            $substitutions = array_merge(
183
                $substitutions,
184
                $this->substitutionRepository->findAllForTeacher($teacher, $current)
185
            );
186
            $current = $current->modify('+1 day');
187
        }
188
189
        $substitutions = array_filter($substitutions, fn(Substitution $substitution) => $substitution->getReplacementTeachers()->contains($teacher));
190
191
        return $this->computeOverview($tuitions, $entries, $comments, $substitutions, $start, $end);
192
    }
193
194
    public function computeOverviewForGrade(Grade $grade, DateTime $start, DateTime $end): EntryOverview {
195
        $section = $this->sectionResolver->getSectionForDate($start);
196
197
        if($section === null) {
198
            return new EntryOverview($start, $end, [ ], [ ], [ ]);
199
        }
200
201
        if($end > $section->getEnd()) {
202
            $end = $section->getEnd();
203
        }
204
205
        $entries = $this->entryRepository->findAllByGrade($grade, $start, $end);
0 ignored issues
show
Bug introduced by
It seems like $end can also be of type null; however, parameter $end of App\Repository\LessonEnt...rface::findAllByGrade() 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

205
        $entries = $this->entryRepository->findAllByGrade($grade, $start, /** @scrutinizer ignore-type */ $end);
Loading history...
206
        $tuitions = $this->tuitionRepository->findAllByGrades([$grade], $section);
207
208
        $comments = [ ];
209
        $section = $this->sectionResolver->getSectionForDate($start);
210
211
        if($section !== null) {
212
            $comments = $this->commentRepository->findAllByDateAndGrade($grade, $section, $start, $end);
0 ignored issues
show
Bug introduced by
It seems like $end can also be of type null; however, parameter $end of App\Repository\BookComme...findAllByDateAndGrade() 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

212
            $comments = $this->commentRepository->findAllByDateAndGrade($grade, $section, $start, /** @scrutinizer ignore-type */ $end);
Loading history...
213
        }
214
215
        return $this->computeOverview($tuitions, $entries, $comments, [ ], $start, $end);
0 ignored issues
show
Bug introduced by
It seems like $end can also be of type null; however, parameter $end of App\Book\EntryOverviewHelper::computeOverview() 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

215
        return $this->computeOverview($tuitions, $entries, $comments, [ ], $start, /** @scrutinizer ignore-type */ $end);
Loading history...
216
    }
217
218
    /**
219
     * @return FreeTimespan[]
220
     */
221
    public function computeFreeTimespans(DateTime $start, DateTime $end): array {
222
        $result = [ ];
223
224
        $categories = array_map(fn(int $id) => $this->appointmentCategoryRepository->findOneById($id), $this->timetableSettings->getCategoryIds());
225
226
        if(count($categories) > 0) {
227
            $appointments = $this->appointmentRepository->findAllStartEnd($start, $end, $categories);
228
229
            foreach($appointments as $appointment) {
230
                $current = clone $appointment->getStart();
231
                while($current < $appointment->getEnd()) {
232
                    $result[] = new FreeTimespan(clone $current, 1, $this->timetableSettings->getMaxLessons(), $appointment->getTitle());
0 ignored issues
show
Bug introduced by
It seems like $appointment->getTitle() can also be of type null; however, parameter $reason of App\Book\FreeTimespan::__construct() does only seem to accept string, 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

232
                    $result[] = new FreeTimespan(clone $current, 1, $this->timetableSettings->getMaxLessons(), /** @scrutinizer ignore-type */ $appointment->getTitle());
Loading history...
233
                    $current = $current->modify('+1 day');
234
                }
235
            }
236
        }
237
238
        // findAllStartEnd queries appointments which includes the end date - but that may cause issues when $start==$end, so manually filter
239
        $result = array_filter($result, fn(FreeTimespan $timespan) => $timespan->getDate() >= $start && $timespan->getDate() <= $end);
240
241
        $current = clone $start;
242
        while($current <= $end) {
243
            $freeTimespans = $this->freeTimespanRepository->findAllByDate($current);
244
245
            foreach($freeTimespans as $timespan) {
246
                $result[] = new FreeTimespan(clone $timespan->getDate(), $timespan->getStart(), $timespan->getEnd(), 'Vertretungsplan');
247
            }
248
249
            $current = $current->modify('+1 day');
250
        }
251
252
        return $result;
253
    }
254
}