Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
CalculateSlots
n/a
0 / 0
n/a
0 / 0
34
n/a
0 / 0
 __construct
n/a
0 / 0
n/a
0 / 0
1
 log
n/a
0 / 0
n/a
0 / 0
2
 dumpLogs
n/a
0 / 0
n/a
0 / 0
3
 getSpendTime
n/a
0 / 0
n/a
0 / 0
1
 readCalculateSkip
n/a
0 / 0
n/a
0 / 0
1
 readForceVerbose
n/a
0 / 0
n/a
0 / 0
2
 readLastRun
n/a
0 / 0
n/a
0 / 0
1
 writeMaintenanceQueries
n/a
0 / 0
n/a
0 / 0
4
 writeCalculations
n/a
0 / 0
n/a
0 / 0
9
 writeCalculatedScope
n/a
0 / 0
n/a
0 / 0
3
 writePostProcessingByScope
n/a
0 / 0
n/a
0 / 0
3
 writeCanceledSlots
n/a
0 / 0
n/a
0 / 0
2
 deleteOldSlots
n/a
0 / 0
n/a
0 / 0
2
1<?php
2
3namespace BO\Zmsdb\Helper;
4
5/**
6 * @codeCoverageIgnore
7 */
8class CalculateSlots
9{
10    protected $verbose = false;
11
12    protected $startTime;
13
14    protected $logList = [];
15
16    public function __construct($verbose = false)
17    {
18        $this->verbose = $verbose;
19        $this->startTime = microtime(true);
20    }
21
22    public function log($message)
23    {
24        $time = $this->getSpendTime();
25        $memory = memory_get_usage() / (1024 * 1024);
26        $text = sprintf("[CalculateSlots %07.3fs %07.1fmb] %s", "$time", $memory, $message);
27        $this->logList[] = $text;
28        if ($this->verbose) {
29            \App::$log->info($message, [
30                'component' => 'CalculateSlots',
31                'elapsed' => $time,
32                'memory_mb' => $memory,
33            ]);
34        }
35        return $this;
36    }
37
38    public function dumpLogs()
39    {
40        foreach ($this->logList as $text) {
41            if (!$this->verbose) {
42                \App::$log->info($text, ['component' => 'CalculateSlots']);
43            }
44        }
45        $this->verbose = true;
46    }
47
48    public function getSpendTime()
49    {
50        $time = round(microtime(true) - $this->startTime, 3);
51        return $time;
52    }
53
54    protected function readCalculateSkip()
55    {
56        $skip = (new \BO\Zmsdb\Config())->readProperty('status__calculateSlotsSkip');
57        return $skip;
58    }
59
60    protected function readForceVerbose()
61    {
62        $force = (new \BO\Zmsdb\Config())->readProperty('status__calculateSlotsForceVerbose');
63        if ($force) {
64            $this->log("Forced verbose, see table config.status__calculateSlotsForceVerbose");
65            $this->dumpLogs();
66        }
67        return $force;
68    }
69
70    protected function readLastRun()
71    {
72        $updateTimestamp = (new \BO\Zmsdb\Config())->readProperty('status__calculateSlotsLastRun', true);
73        return $updateTimestamp;
74    }
75
76    public function writeMaintenanceQueries($daily = false)
77    {
78        $sqlList = (new \BO\Zmsdb\Config())->readProperty('status__calculateSlotsMaintenanceSQL');
79        if ($sqlList) {
80            $pdo = \BO\Zmsdb\Connection\Select::getWriteConnection();
81            foreach (explode("\n", $sqlList) as $sql) {
82                $this->log("Maintenance query: $sql");
83                $pdo->exec($sql);
84            }
85            return \BO\Zmsdb\Connection\Select::writeCommit();
86        }
87
88        if ($daily) {
89            (new \BO\Zmsdb\Slot())->writeOptimizedSlotTables();
90            $this->log("Optimized tables successfully");
91        }
92    }
93
94
95    public function writeCalculations(\DateTimeInterface $now, $daily = false)
96    {
97        \BO\Zmsdb\Connection\Select::setTransaction();
98        \BO\Zmsdb\Connection\Select::getWriteConnection();
99        $this->readForceVerbose();
100        $this->log("Calculate with time " . $now->format('c'));
101        if ($this->readCalculateSkip()) {
102            $this->log("Skip calculation due to config setting status.calculateSlotsSkip");
103            return false;
104        }
105        $startTimestamp = (new \BO\Zmsdb\Config())->readProperty('status__calculateSlotsLastStart', true);
106        $updateTimestamp = (new \BO\Zmsdb\Config())->readProperty('status__calculateSlotsLastRun', false);
107        if ($startTimestamp > $updateTimestamp && ((strtotime($startTimestamp) + (60 * 15)) > $now->getTimestamp())) {
108            $this->log("Skip calculation, last start on $startTimestamp is not yet finished, waiting 15 minutes.");
109            return false;
110        }
111        (new \BO\Zmsdb\Config())->replaceProperty('status__calculateSlotsLastStart', $now->format('Y-m-d H:i:s'));
112        \BO\Zmsdb\Connection\Select::writeCommit();
113        $updateTimestamp = $this->readLastRun();
114        $this->log("Last Run on time=" . $updateTimestamp);
115        if ($daily) {
116            $this->deleteOldSlots($now);
117        }
118        $scopeList = (new \BO\Zmsdb\Scope())->readList(1);
119        $scopeLength = count($scopeList) - 1;
120        foreach ($scopeList as $key => $scope) {
121            if ($this->writeCalculatedScope($scope, $now)) {
122                $this->log("Calculated slots $key/$scopeLength for $scope");
123            }
124        }
125
126        $this->writeCanceledSlots($now);
127
128        $slotQuery = new \BO\Zmsdb\Slot();
129        if ($slotsProcessed = $slotQuery->deleteSlotProcessOnProcess()) {
130            $this->log("Finished to free $slotsProcessed slots for changed/deleted processes");
131        }
132
133        $slotQuery->deleteSlotProcessOnSlot();
134
135        if ($slotsProcessed = $slotQuery->updateSlotProcessMapping()) {
136            $this->log("Updated Slot-Process-Mapping, mapped $slotsProcessed processes");
137        }
138
139        (new \BO\Zmsdb\Config())->replaceProperty('status__calculateSlotsLastRun', $now->format('Y-m-d H:i:s'));
140
141        \BO\Zmsdb\Connection\Select::writeCommit();
142        $this->log("Slot calculation finished");
143        $this->writeMaintenanceQueries($daily);
144
145        return true;
146    }
147
148    protected function writeCalculatedScope(\BO\Zmsentities\Scope $scope, \DateTimeInterface $now)
149    {
150        $slotQuery = new \BO\Zmsdb\Slot();
151        $updatedList = $slotQuery->writeByScope($scope, $now);
152        foreach ($updatedList as $availability) {
153            $this->log("Updated $availability with reason " . json_encode($availability['processingNote']));
154        }
155        if (count($updatedList)) {
156            $this->writePostProcessingByScope($scope, $now);
157            \BO\Zmsdb\Connection\Select::writeCommitWithStartLock();
158            $this->readLastRun();
159            return true;
160        }
161        return false;
162    }
163
164    public function writePostProcessingByScope(\BO\Zmsentities\Scope $scope, \DateTimeInterface $now)
165    {
166        $slotQuery = new \BO\Zmsdb\Slot();
167        if ($slotsProcessed = $slotQuery->deleteSlotProcessOnProcess($scope->id)) {
168            $this->log("Finished to free $slotsProcessed slots for changed/deleted processes");
169        }
170        $slotQuery->writeCanceledByTimeAndScope($now, $scope);
171        $slotQuery->deleteSlotProcessOnSlot($scope->id);
172        //$this->log("Finished to free slots for cancelled availabilities");
173
174        if ($slotsProcessed = $slotQuery->updateSlotProcessMapping($scope->id)) {
175            $this->log("Updated Slot-Process-Mapping, mapped $slotsProcessed processes");
176        }
177    }
178
179    public function writeCanceledSlots(\DateTimeInterface $now, $modify = '+5 minutes')
180    {
181        \BO\Zmsdb\Connection\Select::getWriteConnection();
182        $slotQuery = new \BO\Zmsdb\Slot();
183        if ($slotQuery->writeCanceledByTime($now->modify($modify))) {
184            \BO\Zmsdb\Connection\Select::writeCommit();
185            $this->log("Cancelled slots older than " . $now->modify($modify)->format('c'));
186            return true;
187        }
188        return false;
189    }
190
191    public function deleteOldSlots(\DateTimeInterface $now)
192    {
193        $this->log("Maintenance: Delete slots older than " . $now->format('Y-m-d'));
194        $slotQuery = new \BO\Zmsdb\Slot();
195        $pdo = \BO\Zmsdb\Connection\Select::getWriteConnection();
196        $pdo->exec('SET SESSION innodb_lock_wait_timeout=600');
197        if ($slotQuery->deleteSlotsOlderThan($now)) {
198            \BO\Zmsdb\Connection\Select::writeCommit();
199            $this->log("Deleted old slots successfully");
200        }
201    }
202}