TimetableLessonsImportStrategy::persist()   C
last analyzed

Complexity

Conditions 14
Paths 50

Size

Total Lines 78
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 210

Importance

Changes 0
Metric Value
eloc 47
c 0
b 0
f 0
dl 0
loc 78
rs 6.2666
ccs 0
cts 39
cp 0
cc 14
nc 50
nop 2
crap 210

How to fix   Long Method    Complexity   

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:

1
<?php
2
3
namespace App\Import;
4
5
use App\Entity\Grade;
6
use App\Entity\Room;
7
use App\Entity\Section;
8
use App\Entity\Subject;
9
use App\Entity\Teacher;
10
use App\Entity\TimetableLesson;
11
use App\Entity\Tuition;
12
use App\Repository\GradeRepositoryInterface;
13
use App\Repository\RoomRepositoryInterface;
14
use App\Repository\SubjectRepositoryInterface;
15
use App\Repository\TeacherRepositoryInterface;
16
use App\Repository\TimetableLessonRepositoryInterface;
17
use App\Repository\TransactionalRepositoryInterface;
18
use App\Repository\TuitionRepositoryInterface;
19
use App\Request\Data\TimetableLessonData;
20
use App\Request\Data\TimetableLessonsData;
21
use App\Section\SectionResolver;
22
use App\Section\SectionResolverInterface;
23
use App\Utils\ArrayUtils;
24
use App\Utils\CollectionUtils;
25
use Psr\Log\LoggerInterface;
26
use Ramsey\Uuid\Uuid;
27
28
class TimetableLessonsImportStrategy implements ReplaceImportStrategyInterface, InitializeStrategyInterface {
29
30
    private array $gradeCache;
31
    private array $teacherCache;
32
    private array $roomCache;
33
    private array $subjectCache;
34
    private array $tuitionCache = [ ];
35
36
    public function __construct(private TimetableLessonRepositoryInterface $timetableRepository, private TuitionRepositoryInterface $tuitionRepository, private RoomRepositoryInterface $roomRepository, private TeacherRepositoryInterface $teacherRepository, private SubjectRepositoryInterface $subjectRepository, private GradeRepositoryInterface $gradeRepository, private SectionResolverInterface $sectionResolver, private LoggerInterface $logger)
37
    {
38
    }
39
40
    public function initialize($requestData): void {
41
        $this->gradeCache = ArrayUtils::createArrayWithKeys(
42
            $this->gradeRepository->findAll(),
43
            fn(Grade $grade) => $grade->getExternalId()
44
        );
45
46
        $this->teacherCache = ArrayUtils::createArrayWithKeys(
47
            $this->teacherRepository->findAll(),
48
            fn(Teacher $teacher) => $teacher->getExternalId()
49
        );
50
51
        $this->subjectCache = ArrayUtils::createArrayWithKeys(
52
            $this->subjectRepository->findAll(),
53
            fn(Subject $subject) => $subject->getAbbreviation()
54
        );
55
56
        $this->roomCache = ArrayUtils::createArrayWithKeys(
57
            $this->roomRepository->findAllExternal(),
58
            fn(Room $room) => $room->getExternalId()
59
        );
60
    }
61
62
    /**
63
     * @param string[] $grades
64
     * @param string[] $teachers
65
     * @return Tuition[]
66
     */
67
    private function findTuition(array $grades, array $teachers, string $subjectOrCourse, Section $section): array {
68
        sort($grades);
69
        sort($teachers);
70
71
        $key = sprintf(
72
            '%d-%s-%s-%s',
73
            $section->getId(),
74
            implode('~', $grades),
75
            implode('~', $teachers),
76
            $subjectOrCourse
77
        );
78
79
        if(!isset($this->tuitionCache[$key])) {
80
            $this->tuitionCache[$key] = $this->tuitionRepository->findAllByGradeTeacherAndSubjectOrCourse($grades, $teachers, $subjectOrCourse, $section);
81
        }
82
83
        return $this->tuitionCache[$key];
84
    }
85
86
    /**
87
     * @param TimetableLessonData $data
88
     * @param TimetableLessonsData $requestData
89
     * @throws ImportException
90
     */
91
    public function persist($data, $requestData): void {
92
        $entity = new TimetableLesson();
93
94
        if($data->getDate() < $requestData->getStartDate() || $data->getDate() > $requestData->getEndDate()) {
95
            return;
96
        }
97
98
        $section = $this->sectionResolver->getSectionForDate($data->getDate());
0 ignored issues
show
Bug introduced by
It seems like $data->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

98
        $section = $this->sectionResolver->getSectionForDate(/** @scrutinizer ignore-type */ $data->getDate());
Loading history...
99
100
        if($section === null) {
101
            throw new SectionNotResolvableException($data->getDate());
0 ignored issues
show
Bug introduced by
It seems like $data->getDate() can also be of type null; however, parameter $dateTime of App\Import\SectionNotRes...xception::__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

101
            throw new SectionNotResolvableException(/** @scrutinizer ignore-type */ $data->getDate());
Loading history...
102
        }
103
104
        if(!empty($data->getSubject()) && count($data->getGrades()) > 0 && count($data->getTeachers()) > 0) {
105
            $tuitions = $this->findTuition($data->getGrades(), $data->getTeachers(), $data->getSubject(), $section);
106
107
            if (count($tuitions) === 0) {
108
                $entity->setTuition(null);
109
            } else {
110
                if (count($tuitions) === 1) {
111
                    $entity->setTuition(array_shift($tuitions));
112
                } else {
113
                    $entity->setTuition(null);
114
                }
115
            }
116
        } else {
117
            $entity->setTuition(null);
118
        }
119
120
        if(!empty($data->getRoom())) {
121
            //$room = $this->roomRepository->findOneByExternalId($data->getRoom());
122
            $room = $this->roomCache[$data->getRoom()] ?? null;
123
            $entity->setRoom($room);
124
125
            if($room === null) {
126
                $entity->setLocation($data->getRoom());
127
            }
128
        } else {
129
            $entity->setRoom(null);
130
        }
131
132
        if($data->getSubject() !== null) {
133
            //$subject = $this->subjectRepository->findOneByAbbreviation($data->getSubject());
134
            $subject = $this->subjectCache[$data->getSubject()] ?? null;
135
            $entity->setSubject($subject);
136
        }
137
138
        $entity->setSubjectName($data->getSubject());
139
140
        if($entity->getTuition() === null && $entity->getSubject() === null) {
141
            $this->logger->info(sprintf(
142
                'Kein Unterricht für die Stundenplanstunde mit dem Fach "%s", den Lehrkräften "%s" und Klasse(n) "%s" gefunden.',
143
                $data->getSubject(),
144
                implode(',', $data->getTeachers()),
145
                implode(',', $data->getGrades())
146
            ));
147
        }
148
149
        CollectionUtils::synchronize(
150
            $entity->getGrades(),
151
            ArrayUtils::findAllWithKeys($this->gradeCache, $data->getGrades()),
152
            //$this->gradeRepository->findAllByExternalId($data->getGrades()),
153
            fn(Grade $grade) => $grade->getId()
154
        );
155
156
        CollectionUtils::synchronize(
157
            $entity->getTeachers(),
158
            ArrayUtils::findAllWithKeys($this->teacherCache, $data->getTeachers()),
159
            //$teachers = $this->teacherRepository->findAllByExternalId($data->getTeachers()),
160
            fn(Teacher $teacher) => $teacher->getId()
161
        );
162
163
        $entity->setExternalId($data->getId());
164
        $entity->setDate($data->getDate());
165
        $entity->setLessonStart($data->getLessonStart());
166
        $entity->setLessonEnd($data->getLessonEnd());
167
168
        $this->timetableRepository->persist($entity);
169
    }
170
171
172
    /**
173
     * @inheritDoc
174
     */
175
    public function getRepository(): TransactionalRepositoryInterface {
176
        return $this->timetableRepository;
177
    }
178
179
    /**
180
     * @param TimetableLessonsData $data
181
     * @return TimetableLessonData[]
182
     */
183
    public function getData($data): array {
184
        return $data->getLessons();
185
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190
    public function getEntityClassName(): string {
191
        return TimetableLesson::class;
192
    }
193
194
    /**
195
     * @param TimetableLessonsData $data
196
     */
197
    public function removeAll($data): void {
198
        $this->timetableRepository->removeStartingFrom($data->getStartDate());
0 ignored issues
show
Bug introduced by
It seems like $data->getStartDate() can also be of type null; however, parameter $dateTime of App\Repository\Timetable...e::removeStartingFrom() 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

198
        $this->timetableRepository->removeStartingFrom(/** @scrutinizer ignore-type */ $data->getStartDate());
Loading history...
199
    }
200
}