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