Skip to content

Commit 05010f1

Browse files
committed
refactor: added repository class for session class
1 parent d87a792 commit 05010f1

File tree

7 files changed

+566
-145
lines changed

7 files changed

+566
-145
lines changed

phpmyfaq/api/index.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
/**
4-
* phpMyFAQ REST API: api/v3.0/version
4+
* phpMyFAQ REST API: api/v3.1/version
55
*
66
* This Source Code Form is subject to the terms of the Mozilla Public License,
77
* v. 2.0. If a copy of the MPL was not distributed with this file, You can

phpmyfaq/setup/index.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
/**
44
* The main phpMyFAQ Setup.
5+
*
56
* This script checks the complete environment, writes the database connection
67
* parameters into the file config/database.php and the configuration into the database.
8+
*
79
* This Source Code Form is subject to the terms of the Mozilla Public License,
810
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
911
* obtain one at https://mozilla.org/MPL/2.0/.
@@ -70,7 +72,7 @@
7072
Strings::init();
7173

7274
//
73-
// Set translation class
75+
// Set a translation class
7476
//
7577
try {
7678
Translation::create()

phpmyfaq/src/phpMyFAQ/Administration/Session.php

Lines changed: 14 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,18 @@
2020
namespace phpMyFAQ\Administration;
2121

2222
use phpMyFAQ\Configuration;
23-
use phpMyFAQ\Database;
2423
use stdClass;
2524
use Symfony\Component\HttpFoundation\Request;
2625
use Throwable;
2726

2827
readonly class Session
2928
{
29+
private SessionRepository $repository;
30+
3031
public function __construct(
3132
private Configuration $configuration,
3233
) {
34+
$this->repository = new SessionRepository($configuration);
3335
}
3436

3537
/**
@@ -42,23 +44,9 @@ public function getNumberOfOnlineUsers(int $windowSeconds = 600): int
4244
try {
4345
$minTimestamp = (int) Request::createFromGlobals()->server->get('REQUEST_TIME') - $windowSeconds;
4446
if ($this->configuration->get(item: 'main.enableUserTracking')) {
45-
$query = sprintf(
46-
'SELECT COUNT(DISTINCT user_id) AS cnt FROM %sfaqsessions WHERE time >= %d AND user_id > 0',
47-
Database::getTablePrefix(),
48-
$minTimestamp - (PMF_AUTH_TIMEOUT * 60),
49-
);
47+
$count = $this->repository->countOnlineUsersFromSessions($minTimestamp - (PMF_AUTH_TIMEOUT * 60));
5048
} else {
51-
$query = sprintf(
52-
'SELECT COUNT(*) AS cnt FROM %sfaquser WHERE session_id IS NOT NULL AND session_timestamp >= %d AND success = 1',
53-
Database::getTablePrefix(),
54-
$minTimestamp,
55-
);
56-
}
57-
58-
$result = $this->configuration->getDb()->query($query);
59-
if ($result) {
60-
$row = $this->configuration->getDb()->fetchObject($result);
61-
$count = isset($row->cnt) ? (int) $row->cnt : 0;
49+
$count = $this->repository->countOnlineUsersFromFaqUser($minTimestamp);
6250
}
6351
} catch (Throwable) {
6452
$count = 0;
@@ -69,18 +57,7 @@ public function getNumberOfOnlineUsers(int $windowSeconds = 600): int
6957

7058
public function getTimeFromSessionId(int $sessionId): int
7159
{
72-
$timestamp = 0;
73-
74-
$query = sprintf('SELECT time FROM %sfaqsessions WHERE sid = %d', Database::getTablePrefix(), $sessionId);
75-
76-
$result = $this->configuration->getDb()->query($query);
77-
78-
if ($result) {
79-
$res = $this->configuration->getDb()->fetchObject($result);
80-
$timestamp = (int) $res->time;
81-
}
82-
83-
return $timestamp;
60+
return $this->repository->getTimeBySessionId($sessionId);
8461
}
8562

8663
/**
@@ -94,16 +71,9 @@ public function getTimeFromSessionId(int $sessionId): int
9471
public function getSessionsByDate(int $firstHour, int $lastHour): array
9572
{
9673
$sessions = [];
74+
$rows = $this->repository->getSessionsByDateRange($firstHour, $lastHour);
9775

98-
$query = sprintf(
99-
'SELECT sid, ip, time FROM %sfaqsessions WHERE time > %d AND time < %d ORDER BY time',
100-
Database::getTablePrefix(),
101-
$firstHour,
102-
$lastHour,
103-
);
104-
105-
$result = $this->configuration->getDb()->query($query);
106-
while ($row = $this->configuration->getDb()->fetchObject($result)) {
76+
foreach ($rows as $row) {
10777
$sessions[$row->sid] = [
10878
'ip' => $row->ip,
10979
'time' => $row->time,
@@ -118,17 +88,7 @@ public function getSessionsByDate(int $firstHour, int $lastHour): array
11888
*/
11989
public function getNumberOfSessions(): int
12090
{
121-
$num = 0;
122-
123-
$query = sprintf('SELECT COUNT(sid) as num_sessions FROM %sfaqsessions', Database::getTablePrefix());
124-
125-
$result = $this->configuration->getDb()->query($query);
126-
if ($result) {
127-
$row = $this->configuration->getDb()->fetchObject($result);
128-
$num = (int) $row->num_sessions;
129-
}
130-
131-
return $num;
91+
return $this->repository->countTotalSessions();
13292
}
13393

13494
/**
@@ -139,24 +99,15 @@ public function getNumberOfSessions(): int
13999
*/
140100
public function deleteSessions(int $first, int $last): bool
141101
{
142-
$query = sprintf(
143-
'DELETE FROM %sfaqsessions WHERE time >= %d AND time <= %d',
144-
Database::getTablePrefix(),
145-
$first,
146-
$last,
147-
);
148-
149-
return (bool) $this->configuration->getDb()->query($query);
102+
return $this->repository->deleteSessionsByTimeRange($first, $last);
150103
}
151104

152105
/**
153106
* Deletes all entries in the table.
154107
*/
155108
public function deleteAllSessions(): bool
156109
{
157-
$query = sprintf('DELETE FROM %sfaqsessions', Database::getTablePrefix());
158-
159-
return (bool) $this->configuration->getDb()->query($query);
110+
return $this->repository->deleteAllSessions();
160111
}
161112

162113
/**
@@ -167,21 +118,10 @@ public function deleteAllSessions(): bool
167118
public function getLast30DaysVisits(int $endDate): array
168119
{
169120
$stats = [];
170-
$visits = [];
171121
$completeData = [];
172122
$startDate = strtotime(datetime: '-1 month');
173123

174-
$query = sprintf(
175-
'SELECT time FROM %sfaqsessions WHERE time > %d AND time < %d;',
176-
Database::getTablePrefix(),
177-
$startDate,
178-
$endDate,
179-
);
180-
$result = $this->configuration->getDb()->query($query);
181-
182-
while ($row = $this->configuration->getDb()->fetchObject($result)) {
183-
$visits[] = $row->time;
184-
}
124+
$visits = $this->repository->getSessionTimestamps($startDate, $endDate);
185125

186126
for ($date = $startDate; $date <= $endDate; $date += 86400) {
187127
$stats[date(
@@ -195,7 +135,7 @@ public function getLast30DaysVisits(int $endDate): array
195135
!isset(
196136
$stats[date(
197137
format: 'Y-m-d',
198-
timestamp: (int) $visitDate,
138+
timestamp: $visitDate,
199139
)],
200140
)
201141
) {
@@ -204,7 +144,7 @@ public function getLast30DaysVisits(int $endDate): array
204144

205145
++$stats[date(
206146
format: 'Y-m-d',
207-
timestamp: (int) $visitDate,
147+
timestamp: $visitDate,
208148
)];
209149
}
210150

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<?php
2+
3+
/**
4+
* Session Repository.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public License,
7+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
8+
* obtain one at https://mozilla.org/MPL/2.0/.
9+
*
10+
* @package phpMyFAQ
11+
* @author Thorsten Rinne <thorsten@phpmyfaq.de>
12+
* @copyright 2025 phpMyFAQ Team
13+
* @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14+
* @link https://www.phpmyfaq.de
15+
* @since 2025-12-02
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace phpMyFAQ\Administration;
21+
22+
use phpMyFAQ\Configuration;
23+
use phpMyFAQ\Database;
24+
25+
readonly class SessionRepository
26+
{
27+
public function __construct(
28+
private Configuration $configuration,
29+
) {
30+
}
31+
32+
/**
33+
* Counts distinct user IDs from sessions within a time window.
34+
*/
35+
public function countOnlineUsersFromSessions(int $minTimestamp): int
36+
{
37+
$query = sprintf(
38+
'SELECT COUNT(DISTINCT user_id) AS cnt FROM %sfaqsessions WHERE time >= %d AND user_id > 0',
39+
Database::getTablePrefix(),
40+
$minTimestamp,
41+
);
42+
43+
$result = $this->configuration->getDb()->query($query);
44+
if ($result) {
45+
$row = $this->configuration->getDb()->fetchObject($result);
46+
return isset($row->cnt) ? (int) $row->cnt : 0;
47+
}
48+
49+
return 0;
50+
}
51+
52+
/**
53+
* Counts users with active sessions from the faquser table.
54+
*/
55+
public function countOnlineUsersFromFaqUser(int $minTimestamp): int
56+
{
57+
$query = sprintf(
58+
'SELECT COUNT(*) AS cnt FROM %sfaquser WHERE session_id IS NOT NULL AND session_timestamp >= %d AND success = 1',
59+
Database::getTablePrefix(),
60+
$minTimestamp,
61+
);
62+
63+
$result = $this->configuration->getDb()->query($query);
64+
if ($result) {
65+
$row = $this->configuration->getDb()->fetchObject($result);
66+
return isset($row->cnt) ? (int) $row->cnt : 0;
67+
}
68+
69+
return 0;
70+
}
71+
72+
/**
73+
* Fetches the timestamp for a specific session ID.
74+
*/
75+
public function getTimeBySessionId(int $sessionId): int
76+
{
77+
$query = sprintf('SELECT time FROM %sfaqsessions WHERE sid = %d', Database::getTablePrefix(), $sessionId);
78+
79+
$result = $this->configuration->getDb()->query($query);
80+
81+
if ($result) {
82+
$res = $this->configuration->getDb()->fetchObject($result);
83+
if ($res && isset($res->time)) {
84+
return (int) $res->time;
85+
}
86+
}
87+
88+
return 0;
89+
}
90+
91+
/**
92+
* Fetches all sessions within a time range.
93+
*
94+
* @return array<int, object>
95+
*/
96+
public function getSessionsByDateRange(int $firstHour, int $lastHour): array
97+
{
98+
$query = sprintf(
99+
'SELECT sid, ip, time FROM %sfaqsessions WHERE time > %d AND time < %d ORDER BY time',
100+
Database::getTablePrefix(),
101+
$firstHour,
102+
$lastHour,
103+
);
104+
105+
$result = $this->configuration->getDb()->query($query);
106+
$sessions = [];
107+
108+
while ($row = $this->configuration->getDb()->fetchObject($result)) {
109+
$sessions[] = $row;
110+
}
111+
112+
return $sessions;
113+
}
114+
115+
/**
116+
* Counts the total number of sessions.
117+
*/
118+
public function countTotalSessions(): int
119+
{
120+
$query = sprintf('SELECT COUNT(sid) as num_sessions FROM %sfaqsessions', Database::getTablePrefix());
121+
122+
$result = $this->configuration->getDb()->query($query);
123+
if ($result) {
124+
$row = $this->configuration->getDb()->fetchObject($result);
125+
return (int) $row->num_sessions;
126+
}
127+
128+
return 0;
129+
}
130+
131+
/**
132+
* Deletes sessions within a time range.
133+
*/
134+
public function deleteSessionsByTimeRange(int $first, int $last): bool
135+
{
136+
$query = sprintf(
137+
'DELETE FROM %sfaqsessions WHERE time >= %d AND time <= %d',
138+
Database::getTablePrefix(),
139+
$first,
140+
$last,
141+
);
142+
143+
return (bool) $this->configuration->getDb()->query($query);
144+
}
145+
146+
/**
147+
* Deletes all sessions.
148+
*/
149+
public function deleteAllSessions(): bool
150+
{
151+
$query = sprintf('DELETE FROM %sfaqsessions', Database::getTablePrefix());
152+
153+
return (bool) $this->configuration->getDb()->query($query);
154+
}
155+
156+
/**
157+
* Fetches all session timestamps within a time range.
158+
*
159+
* @return array<int, int>
160+
*/
161+
public function getSessionTimestamps(int $startDate, int $endDate): array
162+
{
163+
$query = sprintf(
164+
'SELECT time FROM %sfaqsessions WHERE time > %d AND time < %d;',
165+
Database::getTablePrefix(),
166+
$startDate,
167+
$endDate,
168+
);
169+
170+
$result = $this->configuration->getDb()->query($query);
171+
$timestamps = [];
172+
173+
while ($row = $this->configuration->getDb()->fetchObject($result)) {
174+
$timestamps[] = (int) $row->time;
175+
}
176+
177+
return $timestamps;
178+
}
179+
}

0 commit comments

Comments
 (0)