Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.43% covered (success)
98.43%
188 / 191
89.47% covered (warning)
89.47%
17 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
Cluster
98.43% covered (success)
98.43%
188 / 191
89.47% covered (warning)
89.47%
17 / 19
65
0.00% covered (danger)
0.00%
0 / 1
 readEntity
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
7
 readResolvedReferences
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 readEntityWithOpenedScopeStatus
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 readList
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 readByScopeId
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 readByDepartmentId
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
5
 readQueueList
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
 readOpenedScopeList
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 readEnabledScopeList
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 readScopeWithShortestWaitingTime
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
7
 readWithScopeWorkstationCount
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 writeImageData
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
4.00
 readImageData
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 deleteImage
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 deleteEntity
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 writeEntity
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 updateEntity
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 writeAssignedScopes
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
3
 removeCache
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
6.56
1<?php
2
3namespace BO\Zmsdb;
4
5use BO\Zmsdb\Application as App;
6use BO\Zmsentities\Cluster as Entity;
7use BO\Zmsentities\Collection\ClusterList as Collection;
8
9/**
10 *
11 * @SuppressWarnings(Public)
12 * @SuppressWarnings(Coupling)
13 * @SuppressWarnings(Complexity)
14 *
15 */
16class Cluster extends Base
17{
18    /**
19    * read entity
20    *
21    * @param
22    * itemId
23    * resolveReferences
24    *
25    * @return Resource Entity
26    */
27    public function readEntity($itemId, $resolveReferences = 0, $disableCache = false)
28    {
29        $cacheKey = "cluster-$itemId-$resolveReferences";
30
31        $cluster = null;
32        if (!$disableCache && App::$cache && App::$cache->has($cacheKey)) {
33            $cluster = App::$cache->get($cacheKey);
34        }
35
36        if (empty($cluster)) {
37            $query = new Query\Cluster(Query\Base::SELECT);
38            $query
39                ->addEntityMapping()
40                ->addResolvedReferences($resolveReferences)
41                ->addConditionClusterId($itemId);
42            $cluster = $this->fetchOne($query, new Entity());
43            if (! $cluster->hasId()) {
44                return null;
45            }
46        }
47
48        if (App::$cache) {
49            App::$cache->set($cacheKey, $cluster);
50        }
51
52        return $this->readResolvedReferences($cluster, $resolveReferences, $disableCache);
53    }
54
55    public function readResolvedReferences(
56        \BO\Zmsentities\Schema\Entity $entity,
57        $resolveReferences,
58        $disableCache = false
59    ) {
60        $entity['scopes'] = (new Scope())->readByClusterId($entity->id, $resolveReferences, $disableCache);
61
62        return $entity;
63    }
64
65    public function readEntityWithOpenedScopeStatus($itemId, \DateTimeInterface $now, $resolveReferences = 0)
66    {
67        $entity = $this->readEntity($itemId, $resolveReferences);
68        foreach ($entity->scopes as $scope) {
69            $scope->setStatusAvailability('isOpened', (new Scope())->readIsOpened($scope->getId(), $now));
70        }
71        return $entity;
72    }
73
74    /**
75    * read list of clusters
76    *
77    * @param
78    * resolveReferences
79    *
80    * @return Resource Collection
81    */
82    public function readList($resolveReferences = 0)
83    {
84        $clusterList = new Collection();
85        $query = new Query\Cluster(Query\Base::SELECT);
86        $query
87            ->addResolvedReferences($resolveReferences)
88            ->addEntityMapping();
89        $result = $this->fetchList($query, new Entity());
90        if (count($result)) {
91            foreach ($result as $entity) {
92                if ($entity instanceof Entity) {
93                    $entity = $this->readResolvedReferences($entity, $resolveReferences);
94                    $clusterList->addEntity($entity);
95                }
96            }
97        }
98        return $clusterList;
99    }
100
101    public function readByScopeId($scopeId, $resolveReferences = 0)
102    {
103        $query = new Query\Cluster(Query\Base::SELECT);
104        $query
105            ->addEntityMapping()
106            ->addResolvedReferences($resolveReferences)
107            ->addConditionScopeId($scopeId);
108        $entity = $this->fetchOne($query, new Entity());
109        if (! $entity->hasId()) {
110            return null;
111        }
112        $entity = $this->readResolvedReferences($entity, $resolveReferences);
113        return $entity;
114    }
115
116    public function readByDepartmentId($departmentId, $resolveReferences = 0, $disableCache = false)
117    {
118        $clusterList = new Collection();
119        $query = new Query\Cluster(Query\Base::SELECT);
120        $query
121            ->addEntityMapping()
122            ->addResolvedReferences($resolveReferences)
123            ->addConditionDepartmentId($departmentId);
124        $result = $this->fetchList($query, new Entity());
125        if (count($result)) {
126            foreach ($result as $entity) {
127                if ($entity instanceof Entity && !$clusterList->hasEntity($entity->id)) {
128                    $entity = $this->readResolvedReferences($entity, $resolveReferences, $disableCache);
129                    $clusterList->addEntity($entity);
130                }
131            }
132        }
133        return $clusterList;
134    }
135
136    /**
137     * get a queueList by cluster id and dateTime
138     *
139     ** @param
140     *            clusterId
141     *            now
142     *
143     * @return Bool
144     */
145    public function readQueueList(
146        $clusterId,
147        \DateTimeInterface $dateTime,
148        $resolveReferences = 0,
149        $withEntities = []
150    ) {
151        $cluster = $this->readEntity($clusterId, 1);
152        $queueList = new \BO\Zmsentities\Collection\QueueList();
153        foreach ($cluster->scopes as $scope) {
154            $scope = (new Scope())->readWithWorkstationCount($scope->id, $dateTime, 0, $withEntities);
155            $scopeQueueList = (new Scope())
156                ->readQueueListWithWaitingTime($scope, $dateTime, $resolveReferences, $withEntities);
157            if (0 < $scopeQueueList->count()) {
158                $queueList->addList($scopeQueueList);
159            }
160        }
161        return $queueList->withSortedWaitingTime();
162    }
163
164    /**
165     * get a scopeList with opened scopes
166     *
167     ** @param
168     *            clusterId
169     *            now
170     *
171     * @return Bool
172     */
173    public function readOpenedScopeList($clusterId, \DateTimeInterface $dateTime)
174    {
175        $scopeList = new \BO\Zmsentities\Collection\ScopeList();
176        $cluster = $this->readEntity($clusterId, 1);
177        if ($cluster && $cluster->toProperty()->scopes->get()) {
178            foreach ($cluster->scopes as $scope) {
179                $availabilityList = (new Availability())->readOpeningHoursListByDate($scope['id'], $dateTime, 2);
180                if ($availabilityList->isOpened($dateTime)) {
181                    $scope->setStatusAvailability('isOpened', true);
182                    $scopeList->addEntity($scope);
183                }
184            }
185        }
186        return $scopeList;
187    }
188
189    public function readEnabledScopeList($clusterId, \DateTimeInterface $dateTime)
190    {
191        $scopeList = new \BO\Zmsentities\Collection\ScopeList();
192        foreach ($this->readOpenedScopeList($clusterId, $dateTime) as $scope) {
193            if ((new Scope())->readIsGivenNumberInContingent($scope['id'])) {
194                $scopeList->addEntity($scope);
195            }
196        }
197        return $scopeList;
198    }
199
200    /**
201     * get the scope with shortest estimated waitingtime
202     *
203     ** @param
204     *            clusterId
205     *            now
206     *
207     * @return Bool
208     */
209    public function readScopeWithShortestWaitingTime($clusterId, \DateTimeInterface $dateTime)
210    {
211        $scopeList = $this->readOpenedScopeList($clusterId, $dateTime)->getArrayCopy();
212        $nextScope = array_shift($scopeList);
213        $preferedScope = null;
214        $preferedWaitingTime = 0;
215        while ($nextScope) {
216            $scope = (new Scope())->readWithWorkstationCount($nextScope->id, $dateTime);
217            $queueList = (new Scope())->readQueueListWithWaitingTime($scope, $dateTime);
218            $data = $scope->getWaitingTimeFromQueueList($queueList, $dateTime);
219            if (
220                $scope->getCalculatedWorkstationCount() > 0 &&
221                $data &&
222                ($data['waitingTimeEstimate'] <= $preferedWaitingTime || 0 == $preferedWaitingTime)
223            ) {
224                $preferedWaitingTime = $data['waitingTimeEstimate'];
225                $preferedScope = $scope;
226            }
227            $nextScope = array_shift($scopeList);
228        }
229        if (! $preferedScope) {
230            throw new Exception\Cluster\ScopesWithoutWorkstationCount();
231        }
232        return $preferedScope;
233    }
234
235    /**
236     * get cluster with scopes workstation count
237     *
238     * * @param
239     * scopeId
240     * now
241     *
242     * @return number
243     */
244    public function readWithScopeWorkstationCount($clusterId, $dateTime, $resolveReferences = 0)
245    {
246        $scopeQuery = new Scope();
247        $scopeList = new \BO\Zmsentities\Collection\ScopeList();
248        $cluster = $this->readEntity($clusterId, $resolveReferences);
249        if ($cluster->toProperty()->scopes->get()) {
250            foreach ($cluster->scopes as $scope) {
251                $entity = $scopeQuery->readWithWorkstationCount($scope->id, $dateTime, $resolveReferences = 0);
252                if ($entity) {
253                    $scopeList->addEntity($entity);
254                }
255            }
256        }
257        $cluster->scopes = $scopeList;
258        return $cluster;
259    }
260
261    /**
262     * update image data for call display image
263     *
264     * @param
265     *         clusterId
266     *         Mimepart entity
267     *
268     * @return Mimepart entity
269     */
270    public function writeImageData($clusterId, \BO\Zmsentities\Mimepart $entity)
271    {
272        if ($entity->mime && $entity->content) {
273            $this->deleteImage($clusterId);
274            $extension = $entity->getExtension();
275            if ($extension == 'jpeg') {
276                $extension = 'jpg'; //compatibility ZMS1
277            }
278            $imageName = 'c_' . $clusterId . '_bild.' . $extension;
279            $this->perform(
280                (new Query\Scope(Query\Base::REPLACE))->getQueryWriteImageData(),
281                array(
282                'imagename' => $imageName,
283                'imagedata' => $entity->content
284                )
285            );
286        }
287        $entity->id = $clusterId;
288        return $entity;
289    }
290
291    /**
292     * read image data
293     *
294     * @param
295     *         clusterId
296     *
297     * @return Mimepart entity
298     */
299    public function readImageData($clusterId)
300    {
301        $imageName = 'c_' . $clusterId . '_bild';
302        $imageData = new \BO\Zmsentities\Mimepart();
303        $fileData = $this->getReader()->fetchAll(
304            (new Query\Scope(Query\Base::SELECT))->getQueryReadImageData(),
305            ['imagename' => "$imageName%"]
306        );
307        if ($fileData) {
308            $imageData->content = $fileData[0]['imagecontent'];
309            $imageData->mime = pathinfo($fileData[0]['imagename'])['extension'];
310        }
311        return $imageData;
312    }
313
314    /**
315     * delete image data for calldisplay image
316     *
317     * @param
318     *         clusterId
319     *
320     * @return Status
321     */
322    public function deleteImage($clusterId)
323    {
324        $imageName = 'c_' . $clusterId . '_bild';
325        $result = $this->perform(
326            (new Query\Scope(Query\Base::DELETE))->getQueryDeleteImage(),
327            array(
328            'imagename' => "$imageName%"
329            )
330        );
331        return $result;
332    }
333
334    /**
335    * remove an cluster
336    *
337    * @param
338    * itemId
339    *
340    * @return Resource Status
341    */
342    public function deleteEntity($itemId)
343    {
344        $result = false;
345        $cluster = $this->readEntity($itemId);
346        $query =  new Query\Cluster(Query\Base::DELETE);
347        $query->addConditionClusterId($itemId);
348        if ($this->deleteItem($query)) {
349            $result = $this->perform(
350                (new Query\Cluster(Query\Base::DELETE))->getQueryDeleteAssignedScopes(),
351                ['clusterId' => $itemId]
352            );
353        }
354
355        $this->removeCache($cluster);
356
357        return $result;
358    }
359
360    /**
361     * write an cluster
362     *
363     * @param
364     * entity
365     *
366     * @return Entity
367     */
368    public function writeEntity(\BO\Zmsentities\Cluster $entity)
369    {
370        $query = new Query\Cluster(Query\Base::INSERT);
371        $values = $query->reverseEntityMapping($entity);
372        $query->addValues($values);
373        $this->writeItem($query);
374        $lastInsertId = $this->getWriter()->lastInsertId();
375        if ($entity->toProperty()->scopes->isAvailable()) {
376            $this->writeAssignedScopes($lastInsertId, $entity->scopes);
377        }
378
379        $this->removeCache($entity);
380
381        return $this->readEntity($lastInsertId, 1, true);
382    }
383
384    /**
385     * update an cluster
386     *
387     * @param
388     * clusterId, entity
389     *
390     * @return Entity
391     */
392    public function updateEntity($clusterId, \BO\Zmsentities\Cluster $entity)
393    {
394        $query = new Query\Cluster(Query\Base::UPDATE);
395        $query->addConditionClusterId($clusterId);
396        $values = $query->reverseEntityMapping($entity);
397        $query->addValues($values);
398        $this->writeItem($query);
399        if ($entity->toProperty()->scopes->isAvailable()) {
400            $this->writeAssignedScopes($clusterId, $entity->scopes);
401        }
402
403        $this->removeCache($entity);
404
405        return $this->readEntity($clusterId, 1, true);
406    }
407
408    /**
409     * create links preferences of a department
410     *
411     * @param
412     *            departmentId,
413     *            links
414     *
415     * @return Boolean
416     */
417    protected function writeAssignedScopes($clusterId, $scopeList)
418    {
419        $cluster = $this->readEntity($clusterId);
420        $this->perform(
421            (new Query\Cluster(Query\Base::DELETE))->getQueryDeleteAssignedScopes(),
422            ['clusterId' => $clusterId]
423        );
424        foreach ($scopeList as $scope) {
425            if (0 < $scope['id']) {
426                $this->perform(
427                    (new Query\Cluster(Query\Base::REPLACE))->getQueryWriteAssignedScopes(),
428                    array(
429                    'clusterId' => $clusterId,
430                    'scopeId' => $scope['id']
431                    )
432                );
433            }
434        }
435
436        $this->removeCache($cluster);
437    }
438
439    public function removeCache($cluster)
440    {
441        if (!App::$cache || !isset($cluster->id)) {
442            return;
443        }
444
445        if (App::$cache->has("cluster-$cluster->id-0")) {
446            App::$cache->delete("cluster-$cluster->id-0");
447        }
448
449        if (App::$cache->has("cluster-$cluster->id-1")) {
450            App::$cache->delete("cluster-$cluster->id-1");
451        }
452
453        if (App::$cache->has("cluster-$cluster->id-2")) {
454            App::$cache->delete("cluster-$cluster->id-2");
455        }
456    }
457}