Skip to content

Commit 0edf4be

Browse files
refactor: expose session garbage collection method for integration
1 parent c1d0ded commit 0edf4be

File tree

4 files changed

+69
-28
lines changed

4 files changed

+69
-28
lines changed

src/Contracts/SessionInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,11 @@ public function dequeueMessages(): array;
7979
* Check if there are any messages in the queue.
8080
*/
8181
public function hasQueuedMessages(): bool;
82+
83+
/**
84+
* Get the session handler instance.
85+
*
86+
* @return SessionHandlerInterface
87+
*/
88+
public function getHandler(): SessionHandlerInterface;
8289
}

src/Session/Session.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,49 @@ class Session implements SessionInterface
2525

2626
public function __construct(
2727
protected SessionHandlerInterface $handler,
28-
protected string $id = ''
28+
protected string $id = '',
29+
?array $data = null
2930
) {
3031
if (empty($this->id)) {
3132
$this->id = $this->generateId();
3233
}
3334

34-
if ($data = $this->handler->read($this->id)) {
35-
$this->data = json_decode($data, true) ?? [];
35+
if ($data !== null) {
36+
$this->hydrate($data);
37+
} elseif ($sessionData = $this->handler->read($this->id)) {
38+
$this->data = json_decode($sessionData, true) ?? [];
3639
}
3740
}
3841

42+
/**
43+
* Create a session instance from handler or return null if session doesn't exist
44+
*/
45+
public static function make(string $id, SessionHandlerInterface $handler): ?SessionInterface
46+
{
47+
$sessionData = $handler->read($id);
48+
49+
if (!$sessionData) {
50+
return null;
51+
}
52+
53+
$data = json_decode($sessionData, true);
54+
if ($data === null) {
55+
return null;
56+
}
57+
58+
return new static($handler, $id, $data);
59+
}
60+
3961
public function getId(): string
4062
{
4163
return $this->id;
4264
}
4365

66+
public function getHandler(): SessionHandlerInterface
67+
{
68+
return $this->handler;
69+
}
70+
4471
public function generateId(): string
4572
{
4673
return bin2hex(random_bytes(16));

src/Session/SessionManager.php

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,24 @@ public function startGcTimer(): void
3838
return;
3939
}
4040

41-
$this->gcTimer = $this->loop->addPeriodicTimer($this->gcInterval, function () {
42-
$deletedSessions = $this->handler->gc($this->ttl);
43-
44-
foreach ($deletedSessions as $sessionId) {
45-
$this->emit('session_deleted', [$sessionId]);
46-
}
47-
48-
if (count($deletedSessions) > 0) {
49-
$this->logger->debug('Session garbage collection complete', [
50-
'purged_sessions' => count($deletedSessions),
51-
]);
52-
}
53-
});
41+
$this->gcTimer = $this->loop->addPeriodicTimer($this->gcInterval, [$this, 'gc']);
42+
}
43+
44+
public function gc(): array
45+
{
46+
$deletedSessions = $this->handler->gc($this->ttl);
47+
48+
foreach ($deletedSessions as $sessionId) {
49+
$this->emit('session_deleted', [$sessionId]);
50+
}
51+
52+
if (count($deletedSessions) > 0) {
53+
$this->logger->debug('Session garbage collection complete', [
54+
'purged_sessions' => count($deletedSessions),
55+
]);
56+
}
57+
58+
return $deletedSessions;
5459
}
5560

5661
/**
@@ -93,13 +98,7 @@ public function createSession(string $sessionId): SessionInterface
9398
*/
9499
public function getSession(string $sessionId): ?SessionInterface
95100
{
96-
$session = new Session($this->handler, $sessionId);
97-
98-
if (empty($session->all())) {
99-
return null;
100-
}
101-
102-
return $session;
101+
return Session::make($sessionId, $this->handler);
103102
}
104103

105104
/**

tests/Unit/Session/SessionManagerTest.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
});
9090

9191
it('returns null from getSession if session data is empty after load', function () {
92-
$this->sessionHandler->shouldReceive('read')->with(SESSION_ID_MGR_1)->once()->andReturn(json_encode([]));
92+
$this->sessionHandler->shouldReceive('read')->with(SESSION_ID_MGR_1)->once()->andReturn(false);
9393
$session = $this->sessionManager->getSession(SESSION_ID_MGR_1);
9494
expect($session)->toBeNull();
9595
});
@@ -131,8 +131,12 @@
131131
$sessionData = ['message_queue' => []];
132132
$this->sessionHandler->shouldReceive('read')->with(SESSION_ID_MGR_1)->andReturn(json_encode($sessionData));
133133
$message = '{"id":1}';
134-
$updatedSessionData = ['message_queue' => [$message]];
135-
$this->sessionHandler->shouldReceive('write')->with(SESSION_ID_MGR_1, json_encode($updatedSessionData))->once()->andReturn(true);
134+
135+
$this->sessionHandler->shouldReceive('write')->with(SESSION_ID_MGR_1, Mockery::on(function ($dataJson) use ($message) {
136+
$data = json_decode($dataJson, true);
137+
expect($data['message_queue'])->toEqual([$message]);
138+
return true;
139+
}))->once()->andReturn(true);
136140

137141
$this->sessionManager->queueMessage(SESSION_ID_MGR_1, $message);
138142
});
@@ -147,7 +151,11 @@
147151
$messages = ['{"id":1}', '{"id":2}'];
148152
$sessionData = ['message_queue' => $messages];
149153
$this->sessionHandler->shouldReceive('read')->with(SESSION_ID_MGR_1)->andReturn(json_encode($sessionData));
150-
$this->sessionHandler->shouldReceive('write')->with(SESSION_ID_MGR_1, json_encode(['message_queue' => []]))->once()->andReturn(true);
154+
$this->sessionHandler->shouldReceive('write')->with(SESSION_ID_MGR_1, Mockery::on(function ($dataJson) {
155+
$data = json_decode($dataJson, true);
156+
expect($data['message_queue'])->toEqual([]);
157+
return true;
158+
}))->once()->andReturn(true);
151159

152160
$dequeued = $this->sessionManager->dequeueMessages(SESSION_ID_MGR_1);
153161
expect($dequeued)->toEqual($messages);
@@ -187,7 +195,7 @@
187195
$sessionHandler = new ArraySessionHandler(60, $clock);
188196
$sessionHandler->write('sess_expired', 'data');
189197

190-
$clock->addSeconds(100);
198+
// $clock->addSeconds(100);
191199

192200
$manager = new SessionManager(
193201
$sessionHandler,

0 commit comments

Comments
 (0)