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

SubstitutionRepository::findAllForStudyGroups()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 44
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 28
c 0
b 0
f 0
dl 0
loc 44
rs 9.1608
ccs 0
cts 26
cp 0
cc 5
nc 16
nop 2
crap 30
1
<?php
2
3
namespace App\Repository;
4
5
use App\Entity\Grade;
6
use App\Entity\Room;
7
use App\Entity\StudyGroup;
8
use App\Entity\StudyGroupType;
9
use App\Entity\Substitution;
10
use App\Entity\Teacher;
11
use App\Utils\ArrayUtils;
12
use DateTime;
13
use Doctrine\ORM\QueryBuilder;
14
15
class SubstitutionRepository extends AbstractTransactionalRepository implements SubstitutionRepositoryInterface {
16
17
    public function findOneById(int $id): ?Substitution {
18
        return $this->em->getRepository(Substitution::class)
19
            ->findOneBy([
20
                'id' => $id
21
            ]);
22
    }
23
24
    public function findOneByExternalId(string $externalId): ?Substitution {
25
        return $this->em->getRepository(Substitution::class)
26
            ->findOneBy([
27
                'externalId' => $externalId
28
            ]);
29
    }
30
31
    /**
32
     * @inheritDoc
33
     */
34
    public function findAll() {
35
        return $this->getDefaultQueryBuilder(null)
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\Substitut...oryInterface::findAll() of App\Entity\Substitution[].
Loading history...
36
            ->getQuery()
37
            ->getResult();
38
    }
39
40
    /**
41
     * @return Substitution[]
42
     */
43
    public function findAllByDate(DateTime $date, bool $excludeNonStudentSubstitutions = false) {
44
        if($excludeNonStudentSubstitutions === false) {
45
            return $this->getDefaultQueryBuilder($date)
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 documented return type App\Entity\Substitution[].
Loading history...
46
                ->getQuery()
47
                ->getResult();
48
        }
49
50
        $qbInner = $this->em->createQueryBuilder();
51
        $qbInner->select('sInner.id')
52
            ->from(Substitution::class, 'sInner')
53
            ->leftJoin('sInner.studyGroups', 'sgInner')
54
            ->leftJoin('sInner.replacementStudyGroups', 'rsgInner');
55
56
        $qbInner->where(
57
            $qbInner->expr()->andX(
58
                $qbInner->expr()->isNull('sgInner.id'),
59
                $qbInner->expr()->isNull('rsgInner.id')
60
            )
61
        );
62
63
        $qb = $this->getDefaultQueryBuilder($date);
64
        $qb->andWhere(
65
            $qb->expr()->notIn('s.id', $qbInner->getDQL())
66
        );
67
68
        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 documented return type App\Entity\Substitution[].
Loading history...
69
    }
70
71
    public function persist(Substitution $substitution): void {
72
        $this->em->persist($substitution);
73
        $this->flushIfNotInTransaction();
74
    }
75
76
    public function remove(Substitution $substitution): void {
77
        $this->em->remove($substitution);
78
        $this->flushIfNotInTransaction();
79
    }
80
81
    public function removeBetween(DateTime $start, DateTime $end): int {
82
        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...
83
            ->delete(Substitution::class, 's')
84
            ->where('s.date >= :start')
85
            ->andWhere('s.date <= :end')
86
            ->setParameter('start', $start)
87
            ->setParameter('end', $end)
88
            ->getQuery()
89
            ->execute();
90
    }
91
92
    /**
93
     * @inheritDoc
94
     */
95
    public function findAllForStudyGroups(array $studyGroups, ?DateTime $date = null) {
96
        $ids = array_map(fn(StudyGroup $studyGroup) => $studyGroup->getId(), $studyGroups);
97
98
        /** @var StudyGroup|null $gradeStudyGroup */
99
        $gradeStudyGroup = ArrayUtils::first($studyGroups, fn(StudyGroup $studyGroup) => $studyGroup->getType() === StudyGroupType::Grade);
100
        /** @var Grade|null $grade */
101
        $grade = $gradeStudyGroup != null ? $gradeStudyGroup->getGrades()->first() : null;
102
        $gradeId = $grade !== null ? $grade->getId() : null;
103
104
        $qbInner = $this->em->createQueryBuilder();
105
        $qbInner->select('sInner.id')
106
            ->from(Substitution::class, 'sInner')
107
            ->leftJoin('sInner.studyGroups', 'sgInner')
108
            ->leftJoin('sInner.replacementStudyGroups', 'rsgInner')
109
            ->leftJoin('sInner.replacementGrades', 'rgInner');
110
111
        if($gradeId !== null) {
112
            $qbInner->where(
113
                $qbInner->expr()->orX(
114
                    $qbInner->expr()->in('sgInner.id', ':ids'),
115
                    $qbInner->expr()->in('rsgInner.id', ':ids'),
116
                    $qbInner->expr()->eq('rgInner.id', ':gradeId')
117
                )
118
            );
119
        } else {
120
            $qbInner->where(
121
                $qbInner->expr()->orX(
122
                    $qbInner->expr()->in('sgInner.id', ':ids'),
123
                    $qbInner->expr()->in('rsgInner.id', ':ids')
124
                )
125
            );
126
        }
127
128
        $qb = $this->getDefaultQueryBuilder($date);
129
        $qb->andWhere(
130
            $qb->expr()->in('s.id', $qbInner->getDQL())
131
        );
132
        $qb->setParameter('ids', $ids);
133
134
        if($gradeId !== null) {
135
            $qb->setParameter('gradeId', $gradeId);
136
        }
137
138
        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\Substitut...findAllForStudyGroups() of App\Entity\Substitution[].
Loading history...
139
    }
140
141
    /**
142
     * @inheritDoc
143
     */
144
    public function findAllForTeacher(Teacher $teacher, ?DateTime $date = null) {
145
        $qbInner = $this->em->createQueryBuilder();
146
        $qbInner->select('sInner.id')
147
            ->from(Substitution::class, 'sInner')
148
            ->leftJoin('sInner.teachers', 'tInner')
149
            ->leftJoin('sInner.replacementTeachers', 'rtInner');
150
151
        $regExp = '[[:<:]]' . $teacher->getAcronym() . '[[:>:]]';
152 1
153 1
        $qbInner->where(
154 1
            $qbInner->expr()->orX(
155 1
                'tInner.id = :id',
156 1
                'rtInner.id = :id',
157 1
                'REGEXP(sInner.remark, :regexp) = true'
158
            )
159 1
        );
160
161 1
        $qb = $this->getDefaultQueryBuilder($date);
162 1
        $qb->andWhere(
163 1
            $qb->expr()->in('s.id', $qbInner->getDQL())
164 1
        );
165 1
        $qb->setParameter('id', $teacher->getId());
166
        $qb->setParameter('regexp', $regExp);
167
168
        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\Substitut...ce::findAllForTeacher() of App\Entity\Substitution[].
Loading history...
169 1
    }
170 1
171 1
    /**
172
     * @inheritDoc
173 1
     */
174 1
    public function findAllForGrade(Grade $grade, ?DateTime $date = null) {
175
        $qbInner = $this->em->createQueryBuilder();
176 1
        $qbInner->select('sInner.id')
177
            ->from(Substitution::class, 'sInner')
178
            ->leftJoin('sInner.studyGroups', 'sgInner')
179
            ->leftJoin('sInner.replacementStudyGroups', 'rsgInner')
180
            ->leftJoin('sgInner.grades', 'sggInner')
181
            ->leftJoin('rsgInner.grades', 'rsggInner')
182
            ->leftJoin('sInner.replacementGrades', 'rgInner');
183
184
        $qbInner->where(
185
            $qbInner->expr()->orX(
186
                $qbInner->expr()->eq('sggInner.id', ':id'),
187
                $qbInner->expr()->eq('rsggInner.id', ':id'),
188
                $qbInner->expr()->eq('rgInner.id', ':id')
189
            )
190
        );
191
192
        $qb = $this->getDefaultQueryBuilder($date);
193
        $qb->andWhere(
194
            $qb->expr()->in('s.id', $qbInner->getDQL())
195
        );
196
        $qb->setParameter('id', $grade->getId());
197
198
        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\Substitut...face::findAllForGrade() of App\Entity\Substitution[].
Loading history...
199
    }
200
201
    /**
202
     * @inheritDoc
203
     */
204
    public function findAllForRooms(array $rooms, ?DateTime $date): array {
205
        $roomIds = array_filter(array_map(fn(Room $room) => $room->getId(), $rooms), fn($input) => !empty($input));
206
207
        $qb = $this->getDefaultQueryBuilder($date);
208
        $qb->leftJoin('s.replacementRooms', 'r')
209
            ->leftJoin('s.rooms', 'rr')
210
            ->andWhere(
211
            $qb->expr()->orX(
212
                $qb->expr()->in('r.id', ':roomIds'),
213
                $qb->expr()->in('rr.id', ':roomIds')
214
            )
215
        );
216
        $qb->setParameter('roomIds', $roomIds);
217
218
        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...
219
    }
220
221
    private function getDefaultQueryBuilder(DateTime $date = null): QueryBuilder {
222
        $qb = $this->em->createQueryBuilder();
223
224
        $qb->select(['s', 't', 'rt', 'sg', 'rsg', 'rg'])
225
            ->from(Substitution::class, 's')
226
            ->leftJoin('s.teachers', 't')
227
            ->leftJoin('s.replacementTeachers', 'rt')
228
            ->leftJoin('s.studyGroups', 'sg')
229
            ->leftJoin('s.replacementStudyGroups', 'rsg')
230
            ->leftJoin('s.replacementGrades', 'rg')
231
            ->orderBy('s.date', 'asc')
232
            ->orderBy('s.lessonStart', 'asc');
233 1
234 1
        if($date !== null) {
235
            $qb
236 1
                ->where('s.date = :date')
237 1
                ->setParameter('date', $date);
238 1
        }
239 1
240 1
        return $qb;
241 1
    }
242 1
243 1
    /*
244 1
     * TODO: The following methods need improvement -> count in database!
245
     */
246 1
    public function countAllByDate(DateTime $date): int {
247
        return count($this->findAllByDate($date));
248
    }
249
250
    public function countAllForStudyGroups(array $studyGroups, ?DateTime $date = null): int {
251
        return count($this->findAllForStudyGroups($studyGroups, $date));
0 ignored issues
show
Bug introduced by
It seems like $this->findAllForStudyGroups($studyGroups, $date) can also be of type integer; however, parameter $value of count() does only seem to accept Countable|array, 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

251
        return count(/** @scrutinizer ignore-type */ $this->findAllForStudyGroups($studyGroups, $date));
Loading history...
252 1
    }
253
254
    public function countAllForTeacher(Teacher $teacher, ?DateTime $date = null): int {
255
        return count($this->findAllForTeacher($teacher, $date));
0 ignored issues
show
Bug introduced by
It seems like $this->findAllForTeacher($teacher, $date) can also be of type integer; however, parameter $value of count() does only seem to accept Countable|array, 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

255
        return count(/** @scrutinizer ignore-type */ $this->findAllForTeacher($teacher, $date));
Loading history...
256
    }
257
258
    public function countAllForGrade(Grade $grade, ?DateTime $date = null): int {
259
        return count($this->findAllForGrade($grade, $date));
0 ignored issues
show
Bug introduced by
It seems like $this->findAllForGrade($grade, $date) can also be of type integer; however, parameter $value of count() does only seem to accept Countable|array, 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

259
        return count(/** @scrutinizer ignore-type */ $this->findAllForGrade($grade, $date));
Loading history...
260
    }
261
}