Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
39.29% covered (danger)
39.29%
33 / 84
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
OverallCalendarRead
39.29% covered (danger)
39.29%
33 / 84
50.00% covered (danger)
50.00%
1 / 2
38.08
0.00% covered (danger)
0.00%
0 / 1
 buildCalendar
10.53% covered (danger)
10.53%
6 / 57
0.00% covered (danger)
0.00%
0 / 1
81.63
 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
34            if ($row['status'] === 'termin') {
35                if ($row['slots'] !== null) {
36                    $time[$seatNo] = [
37                        'seatNo'   => $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                    $time[$seatNo] = [
48                        'seatNo' => $seatNo,
49                        'status' => 'skip'
50                    ];
51                    $info = $lastSlotInfo["$scopeKey|$seatNo"] ?? null;
52                    if ($info && --$info['openSlots'] <= 0) {
53                        unset($lastSlotInfo["$scopeKey|$seatNo"]);
54                    } else {
55                        $lastSlotInfo["$scopeKey|$seatNo"] = $info;
56                    }
57                }
58            } elseif ($row['status'] === 'cancelled') {
59                $time[$seatNo] = [
60                    'seatNo' => $seatNo,
61                    'status' => 'cancelled'
62                ];
63                unset($lastSlotInfo["$scopeKey|$seatNo"]);
64            } else {
65                $time[$seatNo] = [
66                    'seatNo' => $seatNo,
67                    'status' => 'open'
68                ];
69            }
70        }
71
72        foreach ($calendar as &$day) {
73            foreach ($day['scopes'] as &$scope) {
74                foreach ($scope['times'] as $timeKey => $slotInfo) {
75                    ksort($slotInfo['seats']);
76                    $scope['times'][$timeKey] = [
77                        'name'  => $timeKey,
78                        'seats' => array_values($slotInfo['seats']),
79                    ];
80                }
81                $scope['times'] = array_values($scope['times']);
82            }
83            $day['scopes'] = array_values($day['scopes']);
84        }
85        uksort($calendar, fn($a, $b) => strcmp($a, $b));
86
87        return ['days' => array_values($calendar)];
88    }
89
90    public function readResponse(
91        \Psr\Http\Message\RequestInterface $request,
92        \Psr\Http\Message\ResponseInterface $response,
93        array $args
94    ) {
95        (new Helper\User($request))->checkRights('useraccount');
96        $scopeIdCsv = Validator::param('scopeIds')
97            ->isString()->isMatchOf('/^\d+(,\d+)*$/')->assertValid()->getValue();
98        $scopeIds   = array_map('intval', explode(',', $scopeIdCsv));
99
100        $dateFrom   = Validator::param('dateFrom')->isDate('Y-m-d')->assertValid()->getValue();
101        $dateUntil  = Validator::param('dateUntil')->isDate('Y-m-d')->assertValid()->getValue();
102        $updateAfter = Validator::param('updateAfter')->isDatetime()->setDefault(null)->getValue();
103
104        $flatRows = (new CalendarQuery())->readSlots(
105            $scopeIds,
106            $dateFrom,
107            $dateUntil,
108            $updateAfter
109        );
110
111        $structured = $this->buildCalendar($flatRows);
112
113        $msg           = Response\Message::create($request);
114        $msg->data     = $structured;
115        $msg->meta->rows = count($flatRows);
116
117        $response = Render::withLastModified(
118            $response,
119            (new DateTimeImmutable())->getTimestamp(),
120            '0'
121        );
122        return Render::withJson(
123            $response,
124            $msg->setUpdatedMetaData(),
125            $msg->getStatuscode()
126        );
127    }
128}