Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.50% covered (success)
93.50%
187 / 200
66.67% covered (warning)
66.67%
10 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
Department
93.50% covered (success)
93.50%
187 / 200
66.67% covered (warning)
66.67%
10 / 15
67.20
0.00% covered (danger)
0.00%
0 / 1
 readEntity
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
9
 readResolvedReferences
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
2
 readList
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 readEntitiesByIds
92.86% covered (success)
92.86%
13 / 14
0.00% covered (danger)
0.00%
0 / 1
5.01
 readByScopeId
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 readByOrganisationId
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 deleteEntity
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
7
 writeEntity
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
4
 updateEntity
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
 writeDepartmentDayoffs
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
5.01
 writeDepartmentLinks
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
5.02
 writeDepartmentMail
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 updateDepartmentMail
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 readQueueList
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 removeCache
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
9.01
1<?php
2
3namespace BO\Zmsdb;
4
5use BO\Zmsentities\Department as Entity;
6use BO\Zmsentities\Collection\DepartmentList as Collection;
7
8/**
9 * @SuppressWarnings(Coupling)
10 * @SuppressWarnings(Complexity)
11 *
12 */
13class Department extends Base
14{
15    public static $departmentCache = array();
16
17    public function readEntity($departmentId, $resolveReferences = 0, $disableCache = false)
18    {
19        $cacheKey = "department-$departmentId-$resolveReferences";
20
21        if (!$disableCache && \App::$cache && \App::$cache->has($cacheKey)) {
22            $department = \App::$cache->get($cacheKey);
23        }
24
25        if (empty($department)) {
26            $query = new Query\Department(Query\Base::SELECT);
27            $query->addEntityMapping()
28                ->addResolvedReferences($resolveReferences)
29                ->addConditionDepartmentId($departmentId);
30            $department = $this->fetchOne($query, new Entity());
31
32            if (\App::$cache) {
33                \App::$cache->set($cacheKey, $department);
34                if (\App::$log) {
35                    \App::$log->info('Department cache set', ['cache_key' => $cacheKey]);
36                }
37            }
38        }
39
40        if (isset($department['id']) && $department['id']) {
41            $department = $this->readResolvedReferences($department, $resolveReferences, $disableCache);
42            return $department->withOutClusterDuplicates();
43        }
44
45        return null;
46    }
47
48    #[\Override]
49    public function readResolvedReferences(
50        \BO\Zmsentities\Schema\Entity $entity,
51        $resolveReferences,
52        $disableCache = false
53    ) {
54        $entity['links'] = (new Link())->readByDepartmentId($entity->id, $disableCache);
55        $entity['scopes'] = (new Scope())
56            ->readByDepartmentId($entity->id, $resolveReferences - 1, $disableCache)
57            ->sortByContactName();
58        if (0 < $resolveReferences) {
59            $entity['clusters'] = (new Cluster())->readByDepartmentId(
60                $entity->id,
61                $resolveReferences - 1,
62                $disableCache
63            );
64            $entity['dayoff'] = (new DayOff())->readOnlyByDepartmentId($entity->id, $disableCache);
65        }
66        return $entity;
67    }
68
69    public function readList($resolveReferences = 0)
70    {
71        $departmentList = new Collection();
72        $query = new Query\Department(Query\Base::SELECT);
73        $query->addEntityMapping();
74        $query->addResolvedReferences($resolveReferences);
75        $result = $this->fetchList($query, new Entity());
76        if (count($result)) {
77            foreach ($result as $department) {
78                $department = $this->readResolvedReferences($department, $resolveReferences);
79                if ($department instanceof Entity) {
80                    $departmentList->addEntity($department->withOutClusterDuplicates());
81                }
82            }
83        }
84        return $departmentList;
85    }
86
87    public function readEntitiesByIds(array $departmentIds, $resolveReferences = 0)
88    {
89        if (empty($departmentIds)) {
90            return [];
91        }
92
93        $query = new Query\Department(Query\Base::SELECT);
94        $query->addEntityMapping()
95            ->addResolvedReferences($resolveReferences)
96            ->addConditionDepartmentIds($departmentIds);
97
98        $departments = [];
99        $result = $this->fetchList($query, new Entity());
100
101        foreach ($result as $department) {
102            if ($department instanceof Entity) {
103                $department = $this->readResolvedReferences($department, $resolveReferences);
104                if ($department instanceof Entity) {
105                    $departments[$department->id] = $department->withOutClusterDuplicates();
106                }
107            }
108        }
109
110        return $departments;
111    }
112
113    public function readByScopeId($scopeId, $resolveReferences = 0)
114    {
115        $query = new Query\Department(Query\Base::SELECT);
116        $query->addEntityMapping()
117            ->addResolvedReferences($resolveReferences)
118            ->addConditionScopeId($scopeId);
119        $department = $this->fetchOne($query, new Entity());
120        $department = $this->readResolvedReferences($department, $resolveReferences);
121        return (isset($department['id']) && $department['id']) ? $department->withOutClusterDuplicates() : null;
122    }
123
124    public function readByOrganisationId($organisationId, $resolveReferences = 0)
125    {
126        $departmentList = new Collection();
127        $query = new Query\Department(Query\Base::SELECT);
128        $query
129            ->addEntityMapping()
130            ->addResolvedReferences($resolveReferences)
131            ->addConditionOrganisationId($organisationId);
132        $result = $this->fetchList($query, new Entity());
133        if (count($result)) {
134            foreach ($result as $department) {
135                if ($department instanceof Entity) {
136                    $department = $this->readResolvedReferences($department, $resolveReferences);
137                    $departmentList->addEntity($department->withOutClusterDuplicates());
138                }
139            }
140        }
141        return $departmentList;
142    }
143
144    public function deleteEntity($departmentId)
145    {
146        $entity = $this->readEntity($departmentId, 1);
147        if ($entity) {
148            if (
149                0 < $entity->toProperty()->scopes->get()->count()
150                || 0 < $entity->toProperty()->clusters->get()->count()
151            ) {
152                throw new Exception\Department\ScopeListNotEmpty();
153            }
154
155            self::$departmentCache = [];
156            $query = new Query\Department(Query\Base::DELETE);
157            $query->addConditionDepartmentId($departmentId);
158            $entityDelete = $this->deleteItem($query);
159            $emailDelete = $this->perform(Query\Department::QUERY_MAIL_DELETE, array(
160                $departmentId
161            ));
162        }
163
164        $this->removeCache($entity);
165
166        return ($entity && $entityDelete && $emailDelete) ? $entity : null;
167    }
168
169    public function writeEntity(\BO\Zmsentities\Department $entity, $parentId)
170    {
171        self::$departmentCache = [];
172        $query = new Query\Department(Query\Base::INSERT);
173        $values = $query->reverseEntityMapping($entity, $parentId);
174        // get owner by organisation
175        $owner = (new Owner())->readByOrganisationId($parentId);
176        $values['KundenID'] = $owner->id;
177        $query->addValues($values);
178        $this->writeItem($query);
179        $lastInsertId = $this->getWriter()
180            ->lastInsertId();
181        if ($entity->toProperty()->links->isAvailable()) {
182            $this->writeDepartmentLinks($lastInsertId, $entity->links);
183        }
184        if ($entity->toProperty()->dayoff->isAvailable()) {
185            $this->writeDepartmentDayoffs($lastInsertId, $entity->dayoff);
186        }
187        if ($entity->toProperty()->email->isAvailable()) {
188            $this->writeDepartmentMail(
189                $lastInsertId,
190                $entity->email,
191                $entity->sendEmailReminderEnabled,
192                $entity->sendEmailReminderMinutesBefore
193            );
194        }
195
196        $this->removeCache($entity);
197
198        return $this->readEntity($lastInsertId);
199    }
200
201    public function updateEntity($departmentId, \BO\Zmsentities\Department $entity)
202    {
203        self::$departmentCache = [];
204        $query = new Query\Department(Query\Base::UPDATE);
205        $query->addConditionDepartmentId($departmentId);
206        $values = $query->reverseEntityMapping($entity);
207        $query->addValues($values);
208        $this->writeItem($query);
209        if ($entity->toProperty()->links->isAvailable()) {
210            $this->writeDepartmentLinks($departmentId, $entity->links);
211        }
212        if ($entity->toProperty()->dayoff->isAvailable()) {
213            $this->writeDepartmentDayoffs($departmentId, $entity->dayoff);
214        }
215        if ($entity->toProperty()->email->isAvailable()) {
216            $this->updateDepartmentMail(
217                $departmentId,
218                $entity->email,
219                $entity->sendEmailReminderEnabled,
220                $entity->sendEmailReminderMinutesBefore
221            );
222        }
223        $this->removeCache($entity);
224        return $this->readEntity($departmentId, 0, true);
225    }
226
227    protected function writeDepartmentDayoffs($departmentId, $dayoffList)
228    {
229        if (!$departmentId) {
230            throw new Exception\Department\InvalidId();
231        }
232        $existingDayoffs = (new DayOff())->readOnlyByDepartmentId($departmentId);
233        if ($existingDayoffs->count()) {
234            foreach ($existingDayoffs as $item) {
235                $query = new DayOff();
236                $query->deleteEntity($item->getId());
237            }
238        }
239
240        foreach ($dayoffList as $dayoff) {
241            $query = new Query\DayOff(Query\Base::INSERT);
242            $query->addValues(
243                [
244                    'behoerdenid' => $departmentId,
245                    'Feiertag' => $dayoff['name'],
246                    'Datum' => (new \DateTimeImmutable('@' . $dayoff['date']))->format('Y-m-d')
247                ]
248            );
249            $this->writeItem($query);
250        }
251    }
252
253    protected function writeDepartmentLinks($departmentId, $links)
254    {
255        if (!$departmentId) {
256            throw new Exception\Department\InvalidId();
257        }
258        $existingLinks = (new Link())->readByDepartmentId($departmentId);
259        if ($existingLinks->count()) {
260            foreach ($existingLinks as $item) {
261                $query = new Link();
262                $query->deleteEntity($item->getId());
263            }
264        }
265
266        foreach ($links as $link) {
267            $link = new \BO\Zmsentities\Link($link);
268            $query = new Link();
269            $query->writeEntity($link, $departmentId);
270        }
271    }
272
273    protected function writeDepartmentMail(
274        $departmentId,
275        $email,
276        $sendEmailReminderEnabled,
277        $sendEmailReminderMinutesBefore
278    ) {
279        self::$departmentCache = [];
280        $result = $this->perform(Query\Department::QUERY_MAIL_INSERT, array(
281            $departmentId,
282            $email,
283            $sendEmailReminderEnabled,
284            $sendEmailReminderMinutesBefore
285        ));
286        return $result;
287    }
288
289    protected function updateDepartmentMail(
290        $departmentId,
291        $email,
292        $sendEmailReminderEnabled,
293        $sendEmailReminderMinutesBefore
294    ) {
295        self::$departmentCache = [];
296        $query = Query\Department::QUERY_MAIL_UPDATE;
297        return $this->fetchAffected($query, array(
298            'email' => $email,
299            'departmentId' => $departmentId,
300            'sendEmailReminderEnabled' => $sendEmailReminderEnabled,
301            'sendEmailReminderMinutesBefore' => $sendEmailReminderMinutesBefore
302        ));
303    }
304
305    public function readQueueList(
306        $departmentId,
307        \DateTimeInterface $dateTime,
308        $resolveReferences = 0
309    ) {
310        $queueList = new \BO\Zmsentities\Collection\QueueList();
311        $department = $this->readEntity($departmentId, 2);
312
313        foreach ($department->getScopeList() as $scope) {
314            $scope = (new Scope())->readWithWorkstationCount($scope->id, $dateTime);
315            $scopeQueueList = (new Scope())
316                ->readQueueListWithWaitingTime($scope, $dateTime, $resolveReferences);
317            if (0 < $scopeQueueList->count()) {
318                $queueList->addList($scopeQueueList);
319            }
320        }
321        return $queueList;
322    }
323
324    public function removeCache($department)
325    {
326        if (!\App::$cache || !isset($department->id)) {
327            return;
328        }
329
330        $invalidatedKeys = [];
331
332        // Invalidate department entity cache for all resolveReferences levels (0, 1, 2)
333        for ($resolveReferences = 0; $resolveReferences <= 2; $resolveReferences++) {
334            $key = "department-{$department->id}-{$resolveReferences}";
335            if (\App::$cache->has($key)) {
336                \App::$cache->delete($key);
337                $invalidatedKeys[] = $key;
338            }
339        }
340
341        // Invalidate scopeReadByDepartmentId cache for all resolveReferences levels (0, 1, 2)
342        for ($resolveReferences = 0; $resolveReferences <= 2; $resolveReferences++) {
343            $key = "scopeReadByDepartmentId-{$department->id}-{$resolveReferences}";
344            if (\App::$cache->has($key)) {
345                \App::$cache->delete($key);
346                $invalidatedKeys[] = $key;
347            }
348        }
349
350        if (!empty($invalidatedKeys) && \App::$log) {
351            \App::$log->info('Department cache invalidated', [
352                'department_id' => $department->id,
353                'invalidated_keys' => $invalidatedKeys
354            ]);
355        }
356    }
357}