Passed
Push — master ( 168c03...b525a2 )
by Marcel
14:55
created

ExamRepository::getPaginator()   B

Complexity

Conditions 9
Paths 128

Size

Total Lines 68
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 9
eloc 46
nc 128
nop 10
dl 0
loc 68
ccs 0
cts 35
cp 0
crap 90
rs 7.4359
c 3
b 0
f 0

How to fix   Long Method    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\Repository;
4
5
use App\Entity\Exam;
6
use App\Entity\Grade;
7
use App\Entity\Room;
8
use App\Entity\Section;
9
use App\Entity\Student;
10
use App\Entity\StudyGroup;
11
use App\Entity\Teacher;
12
use DateTime;
13
use Doctrine\ORM\QueryBuilder;
14
use Doctrine\ORM\Tools\Pagination\Paginator;
15
16
class ExamRepository extends AbstractTransactionalRepository implements ExamRepositoryInterface {
17 2
18 2
    private function getDefaultQueryBuilder(DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true): QueryBuilder {
19
        $qb = $this->em->createQueryBuilder();
20
21 2
        $qb
22 2
            ->select(['e', 's', 't', 'sg', 'g', 'tt', 'st'])
23 2
            ->from(Exam::class, 'e')
24 2
            ->leftJoin('e.supervisions', 's')
25 2
            ->leftJoin('s.teacher', 'st')
26 2
            ->leftJoin('e.tuitions', 't')
27 2
            ->leftJoin('t.teachers', 'tt')
28 2
            ->leftJoin('t.studyGroup', 'sg')
29 2
            ->leftJoin('sg.grades', 'g');
30
31 2
        if($today !== null) {
32
            $qb->setParameter('today', $today);
33
34
            if($onlyToday === true) {
35
                $qb->where('e.date = :today');
36
            } else {
37
                $qb->where('e.date >= :today');
38
            }
39
        }
40
41 2
        if($onlyPlanned === true) {
42 2
            $qb->andWhere(
43 2
                $qb->expr()->andX(
44 2
                    $qb->expr()->isNotNull('e.date'),
45 2
                    $qb->expr()->isNotNull('e.lessonStart'),
46 2
                    $qb->expr()->isNotNull('e.lessonEnd')
47
                )
48
            );
49
        }
50
51 2
        return $qb;
52
    }
53
54
    public function findOneById(int $id): ?Exam {
55
        return $this->getDefaultQueryBuilder()
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getDefault...)->getOneOrNullResult() could return the type integer which is incompatible with the type-hinted return App\Entity\Exam|null. Consider adding an additional type-check to rule them out.
Loading history...
56
            ->andWhere('e.id = :id')
57
            ->setParameter('id', $id)
58
            ->getQuery()
59
            ->getOneOrNullResult();
60
    }
61
62
    public function findOneByExternalId(string $externalId): ?Exam {
63
        return $this->getDefaultQueryBuilder()
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getDefault...)->getOneOrNullResult() could return the type integer which is incompatible with the type-hinted return App\Entity\Exam|null. Consider adding an additional type-check to rule them out.
Loading history...
64
            ->andWhere('e.externalId = :externalId')
65
            ->setParameter('externalId', $externalId)
66
            ->getQuery()
67
            ->getOneOrNullResult();
68
    }
69
70
    /**
71
     * @inheritDoc
72
     */
73
    public function findAllByIds(array $ids): array {
74
        return $this->getDefaultQueryBuilder()
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getDefault...getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
75
            ->andWhere('e.id IN (:ids)')
76
            ->setParameter('ids', $ids)
77
            ->getQuery()
78
            ->getResult();
79
    }
80
81
    /**
82
     * @inheritDoc
83
     */
84
    public function findAllByTuitions(array $tuitions, ?DateTime $today = null, bool $onlyPlanned = true) {
85
        $qb = $this->getDefaultQueryBuilder($today, false, $onlyPlanned);
86
87
        $qbInner = $this->em->createQueryBuilder()
88
            ->select('eInner.id')
89
            ->from(Exam::class, 'eInner')
90
            ->leftJoin('eInner.tuitions', 'tInner')
91
            ->where($qb->expr()->in('tInner.id', ':tuitions'));
92
93
        $qb
94
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
95
            ->setParameter('tuitions', $tuitions);
96
97
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() also could return the type integer which is incompatible with the return type mandated by App\Repository\ExamRepos...ce::findAllByTuitions() of App\Entity\Exam[].
Loading history...
98
    }
99
100
    /**
101
     * @inheritDoc
102
     */
103
    public function findAllByStudyGroup(StudyGroup $studyGroup, ?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
104
        $qb = $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned);
105
106
        $qbInner = $this->em->createQueryBuilder()
107
            ->select('eInner.id')
108
            ->from(Exam::class, 'eInner')
109
            ->leftJoin('eInner.tuitions', 'tInner')
110
            ->leftJoin('tInner.studyGroup', 'sInner')
111
            ->where('sInner.id = :studyGroup');
112
113
        $qb
114
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
115
            ->setParameter('studyGroup', $studyGroup->getId());
116
117
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() also could return the type integer which is incompatible with the return type mandated by App\Repository\ExamRepos...::findAllByStudyGroup() of App\Entity\Exam[].
Loading history...
118
    }
119
120
    public function findAllDatesByStudyGroup(StudyGroup $studyGroup, ?DateTime $today = null, bool $onlyPlanned = true) {
121
        $qb = $this->getDefaultQueryBuilder($today, false, $onlyPlanned)
122
            ->select(['e.date', 'COUNT(DISTINCT e.id) AS count'])
123
            ->groupBy('e.date');
124
125
        $qbInner = $this->em->createQueryBuilder()
126
            ->select('eInner.id')
127
            ->from(Exam::class, 'eInner')
128
            ->leftJoin('eInner.tuitions', 'tInner')
129
            ->leftJoin('tInner.studyGroup', 'sInner')
130
            ->where('sInner.id = :studyGroup');
131
132
        $qb
133
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
134
            ->setParameter('studyGroup', $studyGroup->getId());
135
136
        return $qb->getQuery()->getScalarResult();
137
    }
138
139
    /**
140
     * @inheritDoc
141
     */
142
    public function findAllByTeacher(Teacher $teacher, ?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
143
        $qb = $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned);
144
145
        $qbInner = $this->em->createQueryBuilder()
146
            ->select('eInner.id')
147
            ->from(Exam::class, 'eInner')
148
            ->leftJoin('eInner.supervisions', 'sInner')
149
            ->leftJoin('eInner.tuitions', 'tInner')
150
            ->leftJoin('tInner.teachers', 'teacherInner')
151
            ->andWhere(
152
                $qb->expr()->orX(
153
                    'teacherInner.id = :teacher',
154
                    'sInner.teacher = :teacher'
155
                )
156
            );
157
158
        $qb
159
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
160
            ->setParameter('teacher', $teacher->getId());
161
162
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() also could return the type integer which is incompatible with the return type mandated by App\Repository\ExamRepos...ace::findAllByTeacher() of App\Entity\Exam[].
Loading history...
163
    }
164
165
    /**
166
     * @inheritDoc
167
     */
168
    public function findAllDatesByTeacher(Teacher $teacher, ?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
169
        $qb = $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned)
170
            ->select(['e.date', 'COUNT(DISTINCT e.id) AS count'])
171
            ->groupBy('e.date');
172
173
        $qbInner = $this->em->createQueryBuilder()
174
            ->select('eInner.id')
175
            ->from(Exam::class, 'eInner')
176
            ->leftJoin('eInner.supervisions', 'sInner')
177
            ->leftJoin('eInner.tuitions', 'tInner')
178
            ->leftJoin('tInner.teachers', 'teacherInner')
179
            ->andWhere(
180
                $qb->expr()->orX(
181
                    'teacherInner.id = :teacher',
182
                    'sInner.teacher = :teacher',
183
                )
184
            );
185
186
        $qb
187
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
188
            ->setParameter('teacher', $teacher->getId());
189
190
        return $qb->getQuery()->getScalarResult();
191
    }
192
193
    /**
194
     * @inheritDoc
195
     */
196
    public function findAllByStudents(array $students, ?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
197
        $qb = $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned);
198
199
        $studentIds = array_map(fn(Student $student) => $student->getId(), $students);
200
201
        $qbInner = $this->em->createQueryBuilder()
202
            ->select('eInner.id')
203
            ->from(Exam::class, 'eInner')
204
            ->leftJoin('eInner.students', 'sInner')
205
            ->where(
206
                $qb->expr()->in('sInner.id', ':studentIds')
207
            );
208
209
        $qb
210
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
211
            ->setParameter('studentIds', $studentIds);
212
213
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() also could return the type integer which is incompatible with the return type mandated by App\Repository\ExamRepos...ce::findAllByStudents() of App\Entity\Exam[].
Loading history...
214
    }
215
216
    /**
217
     * @inheritDoc
218
     */
219
    public function findAllDatesByStudents(array $students, ?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
220
        $qb = $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned)
221
            ->select(['e.date', 'COUNT(DISTINCT e.id) AS count'])
222
            ->groupBy('e.date');
223
224
        $studentIds = array_map(fn(Student $student) => $student->getId(), $students);
225
226
        $qbInner = $this->em->createQueryBuilder()
227
            ->select('eInner.id')
228
            ->from(Exam::class, 'eInner')
229
            ->leftJoin('eInner.students', 'sInner')
230
            ->where(
231
                $qb->expr()->in('sInner.id', ':studentIds')
232
            );
233
234
        $qb
235
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
236
            ->setParameter('studentIds', $studentIds);
237
238
        return $qb->getQuery()->getScalarResult();
239
    }
240
241
    /**
242
     * @inheritDoc
243
     */
244
    public function findAllByGrade(Grade $grade, ?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
245
        $qb = $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned);
246
247
        $qbInner = $this->em->createQueryBuilder()
248
            ->select('eInner.id')
249
            ->from(Exam::class, 'eInner')
250
            ->leftJoin('eInner.tuitions', 'tInner')
251
            ->leftJoin('tInner.studyGroup', 'sgInner')
252
            ->leftJoin('sgInner.grades', 'gInner')
253
            ->where('gInner.id = :grade');
254
255
        $qb
256
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
257
            ->setParameter('grade', $grade->getId());
258
259
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() also could return the type integer which is incompatible with the return type mandated by App\Repository\ExamRepos...rface::findAllByGrade() of App\Entity\Exam[].
Loading history...
260
    }
261
262
    /**
263
     * @inheritDoc
264
     */
265
    public function findAllDatesByGrade(Grade $grade, ?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
266
        $qb = $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned)
267
            ->select(['e.date', 'COUNT(DISTINCT e.id) AS count'])
268
            ->groupBy('e.date');
269
270
        $qbInner = $this->em->createQueryBuilder()
271
            ->select('eInner.id')
272
            ->from(Exam::class, 'eInner')
273
            ->leftJoin('eInner.tuitions', 'tInner')
274
            ->leftJoin('tInner.studyGroup', 'sgInner')
275
            ->leftJoin('sgInner.grades', 'gInner')
276
            ->where('gInner.id = :grade');
277
278
        $qb
279
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
280
            ->setParameter('grade', $grade->getId());
281
282
        return $qb->getQuery()->getScalarResult();
283
    }
284
285
    /**
286
     * @inheritDoc
287
     */
288
    public function findAllByDate(DateTime $today): array {
289
        $qb = $this->getDefaultQueryBuilder($today, true);
290
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
291
    }
292
293
    /**
294
     * @inheritDoc
295
     */
296
    public function findAllByDateAndLesson(DateTime $today, int $lesson): array {
297
        $qb = $this->getDefaultQueryBuilder($today, true);
298
299
        $qb
300
            ->andWhere('e.lessonStart <= :lesson AND e.lessonEnd >= :lesson')
301
            ->setParameter('lesson', $lesson);
302
303
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
304
    }
305
306
    /**
307
     * @inheritDoc
308
     */
309
    public function findAllByRoomAndDate(Room $room, DateTime $today): array {
310
        $qb = $this->getDefaultQueryBuilder($today, true);
311
312
        $qb
313
            ->andWhere('e.room = :room')
314
            ->setParameter('room', $room->getId());
315
316
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
317
    }
318
319
    /**
320
     * @inheritDoc
321
     */
322
    public function findAllByRoomAndDateAndLesson(Room $room, DateTime $today, int $lesson): array {
323
        $qb = $this->getDefaultQueryBuilder($today, true);
324
325
        $qb
326
            ->andWhere('e.lessonStart <= :lesson AND e.lessonEnd >= :lesson')
327
            ->setParameter('lesson', $lesson)
328
            ->andWhere('e.room = :room')
329
            ->setParameter('room', $room->getId());
330
331
        return $qb->getQuery()->getResult();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
332
    }
333
334
    /**
335
     * @inheritDoc
336
     */
337
    public function findAll(?DateTime $today = null, bool $onlyToday = false, bool $onlyPlanned = true) {
338
        return $this->getDefaultQueryBuilder($today, $onlyToday, $onlyPlanned)
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getDefault...getQuery()->getResult() also could return the type integer which is incompatible with the return type mandated by App\Repository\ExamRepositoryInterface::findAll() of App\Entity\Exam[].
Loading history...
339
            ->getQuery()
340
            ->getResult();
341
    }
342
343
    /**
344
     * @inheritDoc
345
     */
346
    public function findAllDates(?DateTime $today = null, bool $onlyPlanned = true) {
347
        return $this->getDefaultQueryBuilder($today, false, $onlyPlanned)
348
            ->select(['e.date', 'COUNT(DISTINCT e.id) AS count'])
349
            ->groupBy('e.date')
350
            ->getQuery()
351
            ->getScalarResult();
352
    }
353
354
    /**
355
     * @inheritDoc
356
     */
357
    public function findAllExternal(DateTime $today = null) {
358
        $qb = $this->getDefaultQueryBuilder($today);
359
360
        return $qb->andWhere($qb->expr()->isNotNull('e.externalId'))
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->andWhere($qb...getQuery()->getResult() also could return the type integer which is incompatible with the return type mandated by App\Repository\ExamRepos...face::findAllExternal() of App\Entity\Exam[].
Loading history...
361
            ->getQuery()
362
            ->getResult();
363
    }
364
365
    public function findAllExternalWithRange(DateTime $start, DateTime $end): array {
366
        $qb = $this->getDefaultQueryBuilder(null)
367
            ->andWhere('e.date >= :start')
368
            ->andWhere('e.date <= :end')
369
            ->setParameter('start', $start)
370
            ->setParameter('end', $end);
371 2
372 2
        return $qb->andWhere($qb->expr()->isNotNull('e.externalId'))
0 ignored issues
show
Bug Best Practice introduced by
The expression return $qb->andWhere($qb...getQuery()->getResult() could return the type integer which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
373
            ->getQuery()
374 2
            ->getResult();
375 2
    }
376 2
377
    public function persist(Exam $exam): void {
378
        $this->em->persist($exam);
379
        $this->flushIfNotInTransaction();
380
    }
381
382 2
    public function remove(Exam $exam): void {
383 2
        $this->em->remove($exam);
384 2
        $this->flushIfNotInTransaction();
385 2
    }
386
387
    public function removeBetween(DateTime $start, DateTime $end): int {
388
        return $this->em->createQueryBuilder()
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->em->create...->getQuery()->execute() could return the type array<mixed,mixed> which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
389
            ->delete(Exam::class, 'e')
390
            ->where('e.date >= :start')
391
            ->andWhere('e.date <= :end')
392
            ->setParameter('start', $start)
393
            ->setParameter('end', $end)
394
            ->getQuery()
395
            ->execute();
396
    }
397
398
    /**
399
     * @inheritDoc
400
     */
401
    public function getPaginator(int $itemsPerPage, int &$page, ?Grade $grade = null, ?Teacher $teacher = null, ?Student $student = null, ?StudyGroup $studyGroup = null, bool $onlyPlanned = true, ?DateTime $today = null, ?DateTime $end = null, ?Section $section = null): Paginator {
402
        $qb = $this->getDefaultQueryBuilder($today, false, $onlyPlanned);
403
404
        if($end !== null) {
405
            $qb->andWhere('e.date <= :end')
406
                ->setParameter('end', $end);
407
        }
408
409
        $qbInner = $this->em->createQueryBuilder()
410
            ->select('eInner.id')
411
            ->from(Exam::class, 'eInner')
412
            ->leftJoin('eInner.tuitions', 'tInner')
413
            ->leftJoin('tInner.studyGroup', 'sgInner')
414
            ->leftJoin('sgInner.grades', 'gInner');
415
416
        if($grade !== null) {
417
            $qbInner->where('gInner.id = :grade');
418
            $qb->setParameter('grade', $grade->getId());
419
        }
420
421
        if($teacher !== null) {
422
            $qbInner
423
                 ->leftJoin('eInner.supervisions', 'sInner')
424
                 ->leftJoin('tInner.teachers', 'ttInner')
425
                 ->andWhere(
426
                     $qbInner->expr()->orX(
427
                         'ttInner.id = :teacher',
428
                         'sInner.teacher = :teacher'
429
                     )
430
                 );
431
             $qb->setParameter('teacher', $teacher->getId());
432
        }
433
434
        if($student !== null) {
435
            $qbInner
436
                ->leftJoin('eInner.students', 'sInner')
437
                ->andWhere('sInner.id = :student');
438
            $qb->setParameter('student', $student->getId());
439
        }
440
441
        if($studyGroup !== null) {
442
            $qbInner
443
                ->andWhere('sgInner.id = :studygroup');
444
            $qb->setParameter('studygroup', $studyGroup->getId());
445
        }
446
447
        if($section !== null) {
448
            $qb->leftJoin('t.section', 'section')
449
                ->andWhere('section.id = :section')
450
                ->setParameter('section', $section->getId());
451
        }
452
453
        $qb
454
            ->andWhere($qb->expr()->in('e.id', $qbInner->getDQL()))
455
            ->orderBy('e.date', 'asc');
456
457
        if(!is_numeric($page) || $page < 1) {
0 ignored issues
show
introduced by
The condition is_numeric($page) is always true.
Loading history...
458
            $page = 1;
459
        }
460
461
        $offset = ($page - 1) * $itemsPerPage;
462
463
        $paginator = new Paginator($qb);
464
        $paginator->getQuery()
465
            ->setMaxResults($itemsPerPage)
466
            ->setFirstResult($offset);
467
468
        return $paginator;
469
    }
470
471
}