Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
39.53% covered (danger)
39.53%
34 / 86
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
OverallCalendarRead
39.53% covered (danger)
39.53%
34 / 86
50.00% covered (danger)
50.00%
1 / 2
72.59
0.00% covered (danger)
0.00%
0 / 1
 buildCalendar
11.86% covered (danger)
11.86%
7 / 59
0.00% covered (danger)
0.00%
0 / 1
169.04
 readResponse
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BO\Zmsapi;
4
5use BO\Slim\Render;
6use BO\Mellon\Validator;
7use BO\Zmsdb\OverallCalendar as CalendarQuery;
8use DateTimeImmutable;
9use DateTimeInterface;
10
11class OverallCalendarRead extends BaseController
12{
13    private function buildCalendar(array $rows, int $defaultSeats = 1): array
14    {
15        $calendar = [];
16        $lastSlotInfo = [];
17
18        foreach ($rows as $row) {
19            $dateKey  = (new DateTimeImmutable($row['time']))->format('Y-m-d');
20            $timeKey  = (new DateTimeImmutable($row['time']))->format('H:i');
21            $scopeKey = (int)$row['scope_id'];
22            $seatNo   = (int)$row['seat'];
23
24            $day   =& $calendar[$dateKey];
25            $scope =& $day['scopes'][$scopeKey];
26            $time  =& $scope['times'][$timeKey]['seats'];
27
28            $day['date']            = (new DateTimeImmutable($dateKey))->getTimestamp();
29            $scope['id']            = $scopeKey;
30            $scope['name']          = $row['scope_name'];
31            $scope['shortName']     = $row['scope_short'];
32            $scope['maxSeats']      = max($scope['maxSeats'] ?? 0, $seatNo, $defaultSeats);
33            $time[$seatNo]['init']  = true;
34
35            if ($row['status'] === 'termin') {
36                if ($row['slots'] !== null) {
37                    $time[$seatNo] = [
38                        'status'    => 'termin',
39                        'processId' => (int)$row['process_id'],
40                        'slots'     => (int)$row['slots'],
41                    ];
42                    $lastSlotInfo["$scopeKey|$seatNo"] = [
43                        'processId' => (int)$row['process_id'],
44                        'openSlots' => (int)$row['slots'] - 1,
45                    ];
46                } else {
47                    $info = $lastSlotInfo["$scopeKey|$seatNo"] ?? null;
48                    if ($info && $info['openSlots'] > 0) {
49                        $time[$seatNo] = ['status' => 'skip'];
50                        $lastSlotInfo["$scopeKey|$seatNo"]['openSlots']--;
51
52                        if ($lastSlotInfo["$scopeKey|$seatNo"]['openSlots'] <= 0) {
53                            unset($lastSlotInfo["$scopeKey|$seatNo"]);
54                        }
55                    } else {
56                        $time[$seatNo] = ['status' => 'skip'];
57                    }
58                }
59            } else {
60                $info = $lastSlotInfo["$scopeKey|$seatNo"] ?? null;
61                if ($info && $info['openSlots'] > 0) {
62                    $time[$seatNo] = ['status' => 'skip'];
63                    $lastSlotInfo["$scopeKey|$seatNo"]['openSlots']--;
64
65                    if ($lastSlotInfo["$scopeKey|$seatNo"]['openSlots'] <= 0) {
66                        unset($lastSlotInfo["$scopeKey|$seatNo"]);
67                    }
68                } else {
69                    $time[$seatNo] = ['status' => 'open'];
70                    unset($lastSlotInfo["$scopeKey|$seatNo"]);
71                }
72            }
73        }
74
75        foreach ($calendar as &$day) {
76            foreach ($day['scopes'] as &$scope) {
77                foreach ($scope['times'] as $timeKey => $slotInfo) {
78                    for ($seatNumber = 1; $seatNumber <= $scope['maxSeats']; $seatNumber++) {
79                        if (!isset($slotInfo['seats'][$seatNumber])) {
80                            $slotInfo['seats'][$seatNumber] = ['status' => 'open'];
81                        }
82                    }
83                    ksort($slotInfo['seats']);
84
85                    $scope['times'][$timeKey] = [
86                        'name'  => $timeKey,
87                        'seats' => array_values($slotInfo['seats']),
88                    ];
89                }
90                $scope['times'] = array_values($scope['times']);
91            }
92            $day['scopes'] = array_values($day['scopes']);
93        }
94        uksort($calendar, function ($a, $b) {
95            return strcmp($a, $b);
96        });
97        return ['days' => array_values($calendar)];
98    }
99
100    public function readResponse(
101        \Psr\Http\Message\RequestInterface $request,
102        \Psr\Http\Message\ResponseInterface $response,
103        array $args
104    ) {
105        (new Helper\User($request))->checkRights('useraccount');
106        $scopeIdCsv = Validator::param('scopeIds')
107            ->isString()->isMatchOf('/^\d+(,\d+)*$/')->assertValid()->getValue();
108        $scopeIds   = array_map('intval', explode(',', $scopeIdCsv));
109
110        $dateFrom   = Validator::param('dateFrom')->isDate('Y-m-d')->assertValid()->getValue();
111        $dateUntil  = Validator::param('dateUntil')->isDate('Y-m-d')->assertValid()->getValue();
112        $updateAfter = Validator::param('updateAfter')->isDatetime()->setDefault(null)->getValue();
113
114        $flatRows = (new CalendarQuery())->readSlots(
115            $scopeIds,
116            $dateFrom,
117            $dateUntil,
118            $updateAfter
119        );
120
121        $structured = $this->buildCalendar($flatRows);
122
123        $msg           = Response\Message::create($request);
124        $msg->data     = $structured;
125        $msg->meta->rows = count($flatRows);
126
127        $response = Render::withLastModified(
128            $response,
129            (new DateTimeImmutable())->getTimestamp(),
130            '0'
131        );
132        return Render::withJson(
133            $response,
134            $msg->setUpdatedMetaData(),
135            $msg->getStatuscode()
136        );
137    }
138}