Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
90 / 90
100.00% covered (success)
100.00%
12 / 12
CRAP
100.00% covered (success)
100.00%
1 / 1
Status
100.00% covered (success)
100.00%
90 / 90
100.00% covered (success)
100.00%
12 / 12
20
100.00% covered (success)
100.00%
1 / 1
 readEntity
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
5
 getTotalActiveSessions
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getActiveSessionsByBehoerdenWithScopes
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
3
 getConfigProblems
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 readDdldUpdateStats
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 readOutdatedSlots
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 readFreeSlots
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 readLastCalculateSlots
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 readMailStats
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 readProcessStats
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 readConfigVariables
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 readStatusVariables
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BO\Zmsdb;
4
5use BO\Zmsentities\Status as Entity;
6
7class Status extends Base
8{
9    /**
10     * Fetch status from db
11     *
12     * @return \BO\Zmsentities\Status
13     */
14    public function readEntity(\DateTimeImmutable $now, $includeProcessStats = true)
15    {
16        $entity = new Entity();
17        $configVariables = $this->readConfigVariables();
18        $statusVariables = $this->readStatusVariables();
19        $nodeConnections = round($statusVariables['Threads_connected'] / $configVariables['max_connections'], 2);
20
21        $entity['database']['problems'] = $this->getConfigProblems($configVariables);
22        $entity['database']['locks'] = $statusVariables['Innodb_row_lock_current_waits'];
23        $entity['database']['threads'] = $statusVariables['Threads_connected'];
24        $entity['database']['nodeConnections'] = $nodeConnections;
25        $entity['database']['clusterStatus'] =
26            array_key_exists('wsrep_ready', $statusVariables) ? $statusVariables['wsrep_ready'] : 'OFF';
27        $entity['database']['logbin'] =
28            array_key_exists('log_bin', $configVariables) ? $configVariables['log_bin'] : 'OFF';
29        $entity['processes'] = $includeProcessStats ? $this->readProcessStats($now) : [];
30
31        if ($includeProcessStats) {
32            $entity['processes'] = $this->readProcessStats($now);
33            $outdated = $this->readOutdatedSlots();
34            $entity['processes']['outdated'] = $outdated['cnt'];
35            $entity['processes']['outdatedOldest'] = $outdated['oldest'];
36            $freeSlots = $this->readFreeSlots();
37            $entity['processes']['freeSlots'] = $freeSlots['cnt'];
38        }
39
40        $entity['mail'] = $this->readMailStats();
41        $entity['sources']['dldb']['last'] = $this->readDdldUpdateStats();
42        $entity['processes']['lastCalculate'] = $this->readLastCalculateSlots();
43        $entity['useraccounts']['activeSessions'] = $this->getTotalActiveSessions();
44        $entity['useraccounts']['departments'] = $this->getActiveSessionsByBehoerdenWithScopes();
45
46        return $entity;
47    }
48
49    /**
50     * Get total active sessions where SessionID is not null or empty and sessionExpiry is in the future
51     *
52     * @return int
53     */
54    protected function getTotalActiveSessions()
55    {
56        $result = $this->getReader()->fetchOne(
57            'SELECT COUNT(n.SessionID) as totalActiveSessions
58             FROM nutzer n
59             WHERE n.SessionID IS NOT NULL
60             AND n.SessionID != ""
61             AND n.sessionExpiry > UNIX_TIMESTAMP()'
62        );
63
64        return (int) $result['totalActiveSessions'];
65    }
66
67    /**
68     * Get active sessions grouped by BehoerdenID with scopes, excluding expired sessions
69     *
70     * @return array
71     */
72    protected function getActiveSessionsByBehoerdenWithScopes()
73    {
74        $result = $this->getReader()->fetchAll(
75            'SELECT b.BehoerdenID, b.Name as BehoerdeName, 
76                    s.StandortID, s.Bezeichnung as StandortName,
77                    COALESCE(SUM(CASE 
78                        WHEN n.sessionExpiry > UNIX_TIMESTAMP()
79                        THEN 1 ELSE 0 END), 0) as activeSessions
80             FROM behoerde b
81             LEFT JOIN standort s ON b.BehoerdenID = s.BehoerdenID
82             LEFT JOIN nutzer n ON s.StandortID = n.StandortID
83             GROUP BY b.BehoerdenID, b.Name, s.StandortID, s.Bezeichnung'
84        );
85
86        $activeSessionsByBehoerden = [];
87
88        foreach ($result as $row) {
89            $behoerdenID = $row['BehoerdenID'];
90            $standortID = $row['StandortID'];
91
92            if (!isset($activeSessionsByBehoerden[$behoerdenID])) {
93                $activeSessionsByBehoerden[$behoerdenID] = [
94                    'activeSessions' => 0,
95                    'name' => $row['BehoerdeName'],
96                    'scopes' => []
97                ];
98            }
99
100            $activeSessionsByBehoerden[$behoerdenID]['scopes'][$standortID] = [
101                'activeSessions' => (int) $row['activeSessions'],
102                'name' => $row['StandortName']
103            ];
104
105            $activeSessionsByBehoerden[$behoerdenID]['activeSessions'] += (int) $row['activeSessions'];
106        }
107
108        return $activeSessionsByBehoerden;
109    }
110
111    /**
112     * Get the configuration problems
113     *
114     * @return string
115     */
116    public function getConfigProblems($configVariables)
117    {
118        $problems = [];
119        if ($configVariables['tmp_table_size'] < 32000000) {
120            $problems[] = 'tmp_table_size should be at least 32MB';
121        }
122        if ($configVariables['max_heap_table_size'] < 32000000) {
123            $problems[] = 'max_heap_table_size should be at least 32MB';
124        }
125        return implode('; ', $problems);
126    }
127
128    /**
129     * Get the dldb update status
130     *
131     * @return array
132     */
133    protected function readDdldUpdateStats()
134    {
135        $stats = $this->getReader()->fetchOne(
136            'SELECT value FROM config WHERE name = "sources_dldb_last"'
137        );
138        return $stats['value'];
139    }
140
141    /**
142     * Get outdated slots
143     *
144     * @return array
145     */
146    protected function readOutdatedSlots()
147    {
148        $stats = $this->getReader()->fetchOne(
149            'SELECT COUNT(*) cnt, MIN(a.updateTimestamp) oldest
150             FROM slot s 
151             LEFT JOIN oeffnungszeit a ON s.availabilityID = a.OeffnungszeitID
152             WHERE s.updateTimestamp < a.updateTimestamp AND s.status = "free"'
153        );
154        return $stats;
155    }
156
157    /**
158     * Get free slots count
159     *
160     * @return array
161     */
162    protected function readFreeSlots()
163    {
164        $stats = $this->getReader()->fetchOne(
165            'SELECT SUM(intern) cnt FROM slot s WHERE s.status = "free"'
166        );
167        return $stats;
168    }
169
170    /**
171     * Get last calculate slots information
172     *
173     * @return array
174     */
175    protected function readLastCalculateSlots()
176    {
177        $stats = $this->getReader()->fetchOne(
178            'SELECT value FROM config WHERE name = "status__calculateSlotsLastRun"'
179        );
180        return $stats['value'];
181    }
182
183    /**
184     * Get mail stats
185     *
186     * @return array
187     */
188    protected function readMailStats()
189    {
190        $stats = $this->getReader()->fetchOne(
191            'SELECT COUNT(id) as queueCount, UNIX_TIMESTAMP() - MIN(createTimestamp) as oldestSeconds, 
192                UNIX_TIMESTAMP() - MAX(createTimestamp) as newestSeconds
193             FROM mailqueue'
194        );
195        return $stats;
196    }
197
198    /**
199     * Get process statistics
200     *
201     * @return array
202     */
203    protected function readProcessStats(\DateTimeImmutable $now)
204    {
205        $midnight = $now->modify('00:00:00')->getTimestamp();
206        $last7days = $now->modify('-7 days 00:00:00')->getTimestamp();
207
208        $processStats = $this->getReader()->fetchOne(
209            'SELECT
210                COALESCE(SUM(CASE WHEN b.status = "blocked" THEN 1 ELSE 0 END), 0) AS blocked,
211                COALESCE(SUM(CASE WHEN b.status = "confirmed" THEN 1 ELSE 0 END), 0) AS confirmed,
212                COALESCE(SUM(CASE WHEN b.status = "pending" THEN 1 ELSE 0 END), 0) AS pending,
213                COALESCE(SUM(CASE WHEN b.status = "deleted" THEN 1 ELSE 0 END), 0) AS deleted,
214                COALESCE(SUM(CASE WHEN b.status = "missed" THEN 1 ELSE 0 END), 0) AS missed,
215                COALESCE(SUM(CASE WHEN b.status = "parked" THEN 1 ELSE 0 END), 0) AS parked,
216                COALESCE(SUM(CASE WHEN b.status = "reserved" THEN 1 ELSE 0 END), 0) AS reserved,
217                global.sinceMidnight,
218                global.last7days,
219                global.lastInsert
220             FROM buerger AS b
221             CROSS JOIN (
222                SELECT
223                    COALESCE(SUM(
224                        CASE
225                            WHEN IPTimeStamp > ' . intval($midnight) . 
226                                 AND StandortID != 0
227                                 AND vorlaeufigeBuchung = 0
228                                 AND Abholer = 0
229                            THEN 1 ELSE 0
230                        END
231                    ), 0) AS sinceMidnight,
232                    COALESCE(SUM(
233                        CASE
234                            WHEN IPTimeStamp > ' . intval($last7days) . 
235                                 AND StandortID != 0
236                                 AND vorlaeufigeBuchung = 0
237                                 AND Abholer = 0
238                            THEN 1 ELSE 0
239                        END
240                    ), 0) AS last7days,
241                    FROM_UNIXTIME(MAX(IPTimeStamp)) AS lastInsert
242                FROM buerger
243                WHERE istFolgeterminvon IS NULL OR istFolgeterminvon = 0
244             ) AS global
245             WHERE b.istFolgeterminvon IS NULL OR b.istFolgeterminvon = 0'
246        );
247        return $processStats;
248    }
249
250    /**
251     * Fetch MySQL config variables
252     *
253     * @return array
254     */
255    protected function readConfigVariables()
256    {
257        return $this->getReader()->fetchPairs('SHOW VARIABLES');
258    }
259
260    /**
261     * Fetch MySQL status variables
262     *
263     * @return array
264     */
265    protected function readStatusVariables()
266    {
267        return $this->getReader()->fetchPairs('SHOW STATUS');
268    }
269}