Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f0407aa

Browse files
committed
PHPORM-310 Create dedicated session handler
1 parent c3bab3c commit f0407aa

File tree

3 files changed

+142
-12
lines changed

3 files changed

+142
-12
lines changed

‎src/MongoDBServiceProvider.php‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
use MongoDB\Laravel\Eloquent\Model;
2424
use MongoDB\Laravel\Queue\MongoConnector;
2525
use MongoDB\Laravel\Scout\ScoutEngine;
26+
use MongoDB\Laravel\Session\MongoDbSessionHandler;
2627
use RuntimeException;
27-
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler;
2828

2929
use function assert;
3030
use function class_exists;
@@ -67,12 +67,10 @@ public function register()
6767
assert($connection instanceof Connection, new InvalidArgumentException(sprintf('The database connection "%s" used for the session does not use the "mongodb" driver.', $connectionName)));
6868

6969
return new MongoDbSessionHandler(
70-
$connection->getClient(),
71-
$app->config->get('session.options', []) + [
72-
'database' => $connection->getDatabaseName(),
73-
'collection' => $app->config->get('session.table') ?: 'sessions',
74-
'ttl' => $app->config->get('session.lifetime'),
75-
],
70+
$connection,
71+
$app->config->get('session.table', 'sessions'),
72+
$app->config->get('session.lifetime'),
73+
$app,
7674
);
7775
});
7876
});
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace MongoDB\Laravel\Session;
13+
14+
use Illuminate\Session\DatabaseSessionHandler;
15+
use MongoDB\BSON\Binary;
16+
use MongoDB\BSON\UTCDateTime;
17+
use MongoDB\Collection;
18+
19+
use function tap;
20+
use function time;
21+
22+
/**
23+
* Session handler using the MongoDB driver extension.
24+
*/
25+
final class MongoDbSessionHandler extends DatabaseSessionHandler
26+
{
27+
private Collection $collection;
28+
29+
public function close(): bool
30+
{
31+
return true;
32+
}
33+
34+
public function gc($lifetime): int
35+
{
36+
$result = $this->getCollection()->deleteMany(['last_activity' => ['$lt' => $this->getUTCDateTime(-$lifetime)]]);
37+
38+
return $result->getDeletedCount() ?? 0;
39+
}
40+
41+
public function destroy($sessionId): bool
42+
{
43+
$this->getCollection()->deleteOne(['_id' => (string) $sessionId]);
44+
45+
return true;
46+
}
47+
48+
public function read($sessionId): string|false
49+
{
50+
$result = $this->getCollection()->findOne(
51+
['_id' => (string) $sessionId, 'expires_at' => ['$gte' => $this->getUTCDateTime()]],
52+
[
53+
'projection' => ['_id' => false, 'payload' => true],
54+
'typeMap' => ['root' => 'bson'],
55+
],
56+
);
57+
58+
return $result ? (string) $result->payload : false;
59+
}
60+
61+
public function write($sessionId, $data): bool
62+
{
63+
$payload = $this->getDefaultPayload($data);
64+
65+
$this->getCollection()->replaceOne(
66+
['_id' => (string) $sessionId],
67+
$payload,
68+
['upsert' => true],
69+
);
70+
71+
return true;
72+
}
73+
74+
/** Creates a TTL index that automatically deletes expired objects. */
75+
public function createTTLIndex(): void
76+
{
77+
$this->collection->createIndex(
78+
// UTCDateTime field that holds the expiration date
79+
['expires_at' => 1],
80+
// Delay to remove items after expiration
81+
['expireAfterSeconds' => 0],
82+
);
83+
}
84+
85+
protected function getDefaultPayload($data): array
86+
{
87+
$payload = [
88+
'payload' => new Binary($data),
89+
'last_activity' => $this->getUTCDateTime(),
90+
'expires_at' => $this->getUTCDateTime($this->minutes * 60),
91+
];
92+
93+
if (! $this->container) {
94+
return $payload;
95+
}
96+
97+
return tap($payload, function (&$payload) {
98+
$this->addUserInformation($payload)
99+
->addRequestInformation($payload);
100+
});
101+
}
102+
103+
private function getCollection(): Collection
104+
{
105+
return $this->collection ??= $this->connection->getCollection($this->table);
106+
}
107+
108+
private function getUTCDateTime(int $additionalSeconds = 0): UTCDateTime
109+
{
110+
return new UTCDateTime((time() + $additionalSeconds * 60) * 1000);
111+
}
112+
}

‎tests/SessionTest.php‎

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
use Illuminate\Session\DatabaseSessionHandler;
66
use Illuminate\Session\SessionManager;
77
use Illuminate\Support\Facades\DB;
8-
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler;
8+
use MongoDB\Laravel\Session\MongoDbSessionHandler;
9+
use PHPUnit\Framework\Attributes\TestWith;
10+
use SessionHandlerInterface;
911

1012
class SessionTest extends TestCase
1113
{
@@ -16,21 +18,31 @@ protected function tearDown(): void
1618
parent::tearDown();
1719
}
1820

19-
public function testDatabaseSessionHandlerCompatibility()
21+
/** @param class-string<SessionHandlerInterface> $class */
22+
#[TestWith([DatabaseSessionHandler::class])]
23+
#[TestWith([MongoDbSessionHandler::class])]
24+
public function testSessionHandlerFunctionality(string $class)
2025
{
21-
$sessionId = '123';
22-
23-
$handler = new DatabaseSessionHandler(
26+
$handler = new $class(
2427
$this->app['db']->connection('mongodb'),
2528
'sessions',
2629
10,
2730
);
2831

32+
$sessionId = '123';
33+
2934
$handler->write($sessionId, 'foo');
3035
$this->assertEquals('foo', $handler->read($sessionId));
3136

3237
$handler->write($sessionId, 'bar');
3338
$this->assertEquals('bar', $handler->read($sessionId));
39+
40+
$handler->destroy($sessionId);
41+
$this->assertEmpty($handler->read($sessionId));
42+
43+
$handler->write($sessionId, 'bar');
44+
$handler->gc(-1);
45+
$this->assertEmpty($handler->read($sessionId));
3446
}
3547

3648
public function testDatabaseSessionHandlerRegistration()
@@ -70,5 +82,13 @@ private function assertSessionCanStoreInMongoDB(SessionManager $session): void
7082

7183
self::assertIsObject($data);
7284
self::assertSame($session->getId(), $data->_id);
85+
86+
$session->remove('foo');
87+
$data = DB::connection('mongodb')
88+
->getCollection('sessions')
89+
->findOne(['_id' => $session->getId()]);
90+
91+
self::assertIsObject($data);
92+
self::assertSame($session->getId(), $data->_id);
7393
}
7494
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /