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