8000 Reimplement Lock & Session using only ext-mongodb · symfony/symfony@a2d9ef1 · GitHub
[go: up one dir, main page]

Skip to content

Commit a2d9ef1

Browse files
committed
Reimplement Lock & Session using only ext-mongodb
1 parent 382564d commit a2d9ef1

File tree

12 files changed

+388
-248
lines changed

12 files changed

+388
-248
lines changed

.github/workflows/integration-tests.yml

Lines changed: 0 additions & 1 deletion
8000
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ jobs:
159159
echo COMPOSER_ROOT_VERSION=$COMPOSER_ROOT_VERSION >> $GITHUB_ENV
160160
161161
echo "::group::composer update"
162-
composer require --dev --no-update mongodb/mongodb
163162
composer update --no-progress --ansi
164163
echo "::endgroup::"
165164

.github/workflows/unit-tests.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,6 @@ jobs:
190190
exit 0
191191
fi
192192
193-
(cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb)
194-
(cd src/Symfony/Component/Lock; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb)
195-
196193
# matrix.mode = high-deps
197194
echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} 'cd {} && $COMPOSER_UP && $PHPUNIT$LEGACY'" || X=1
198195
@@ -211,8 +208,6 @@ jobs:
211208
git fetch --depth=2 origin $SYMFONY_VERSION
212209
git checkout -m FETCH_HEAD
213210
PATCHED_COMPONENTS=$(echo "$PATCHED_COMPONENTS" | xargs dirname | xargs -n1 -I{} bash -c "[ -e '{}/phpunit.xml.dist' ] && echo '{}'" | sort || true)
214-
(cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb)
215-
(cd src/Symfony/Component/Lock; composer require --dev --no-update mongodb/mongodb)
216211
if [[ $PATCHED_COMPONENTS ]]; then
217212
echo "::group::install phpunit"
218213
./phpunit install

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ CHANGELOG
99
* Add `UriSigner` from the HttpKernel component
1010
* Add `partitioned` flag to `Cookie` (CHIPS Cookie)
1111
* Add argument `bool $flush = true` to `Response::send()`
12+
* `MongoDbSessionHandler` can be used with the mongodb extension only
1213

1314
6.3
1415
---

src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,22 @@
1414
use MongoDB\BSON\Binary;
1515
use MongoDB\BSON\UTCDateTime;
1616
use MongoDB\Client;
17-
use MongoDB\Collection;
17+
use MongoDB\Driver\BulkWrite;
18+
use MongoDB\Driver\Manager;
19+
use MongoDB\Driver\Query;
1820

1921
/**
20-
* Session handler using the mongodb/mongodb package and MongoDB driver extension.
22+
* Session handler using the MongoDB driver extension.
2123
*
2224
* @author Markus Bachmann <markus.bachmann@bachi.biz>
25+
* @author Jérôme Tamarelle <jerome@tamarelle.net>
2326
*
24-
* @see https://packagist.org/packages/mongodb/mongodb
2527
* @see https://php.net/mongodb
2628
*/
2729
class MongoDbSessionHandler extends AbstractSessionHandler
2830
{
29-
private Client $mongo;
30-
private Collection $collection;
31+
private Manager $manager;
32+
private string $namespace;
3133
private array $options;
3234
private int|\Closure|null $ttl;
3335

@@ -62,13 +64,18 @@ class MongoDbSessionHandler extends AbstractSessionHandler
6264
*
6365
* @throws \InvalidArgumentException When "database" or "collection" not provided
6466
*/
65-
public function __construct(Client $mongo, array $options)
67+
public function __construct(Client|Manager $mongo, array $options)
6668
{
6769
if (!isset($options['database']) || !isset($options['collection'])) {
6870
throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler.');
6971
}
7072

71-
$this->mongo = $mongo;
73+
if ($mongo instanceof Client) {
74+
$mongo = $mongo->getManager();
75+
}
76+
77+
$this->manager = $mongo;
78+
$this->namespace = $options['database'].'.'.$options['collection'];
7279

7380
$this->options = array_merge([
7481
'id_field' => '_id',
@@ -86,77 +93,97 @@ public function close(): bool
8693

8794
protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool
8895
{
89-
$this->getCollection()->deleteOne([
90-
$this->options['id_field'] => $sessionId,
91-
]);
96+
$write = new BulkWrite();
97+
$write->delete(
98+
[$this->options['id_field'] => $sessionId],
99+
['limit' => 1]
100+
);
101+
102+
$this->manager->executeBulkWrite($this->namespace, $write);
92103

93104
return true;
94105
}
95106

96107
public function gc(int $maxlifetime): int|false
97108
{
98-
return $this->getCollection()->deleteMany([
99-
$this->options['expiry_field'] => ['$lt' => new UTCDateTime()],
100-
])->getDeletedCount();
109+
$write = new BulkWrite();
110+
$write->delete(
111+
[$this->options['expiry_field'] => ['$lt' => $this->getUTCDateTime()]],
112+
);
113+
$result = $this->manager->executeBulkWrite($this->namespace, $write);
114+
115+
return $result->getDeletedCount() ?? false;
101116
}
102117

103118
protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool
104119
{
105120
$ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime');
106-
$expiry = new UTCDateTime((time() + (int) $ttl) * 1000);
121+
$expiry = $this->getUTCDateTime($ttl);
107122

108123
$fields = [
109-
$this->options['time_field'] => new UTCDateTime(),
124+
$this->options['time_field'] => $this->getUTCDateTime(),
110125
$this->options['expiry_field'] => $expiry,
111126
$this->options['data_field'] => new Binary($data, Binary::TYPE_OLD_BINARY),
112127
];
113128

114-
$this->getCollection()->updateOne(
129+
$write = new BulkWrite();
130+
$write->update(
115131
[$this->options['id_field'] => $sessionId],
116132
['$set' => $fields],
117133
['upsert' => true]
118134
);
119135

136+
$this->manager->executeBulkWrite($this->namespace, $write);
137+
120138
return true;
121139
}
122140

123141
public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool
124142
{
125143
$ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime');
126-
$expiry = new UTCDateTime((time() + (int) $ttl) * 1000);
144+
$expiry = $this->getUTCDateTime($ttl);
127145

128-
$this->getCollection()->updateOne(
146+
$write = new BulkWrite();
147+
$write->update(
129148
[$this->options['id_field'] => $sessionId],
130149
['$set' => [
131-
$this->options['time_field'] => new UTCDateTime(),
150+
$this->options['time_field'] => $this->getUTCDateTime(),
132151
$this->options['expiry_field'] => $expiry,
133-
]]
152+
]],
153+
['multi' => false],
134154
);
135155

156+
$this->manager->executeBulkWrite($this->namespace, $write);
157+
136158
return true;
137159
}
138160

139161
protected function doRead(#[\SensitiveParameter] string $sessionId): string
140162
{
141-
$dbData = $this->getCollection()->findOne([
163+
$dbData = $this->manager->executeQuery($this->namespace, new Query([
142164
$this->options['id_field'] => $sessionId,
143-
$this->options['expiry_field'] => ['$gte' => new UTCDateTime()],
144-
]);
145-
146-
if (null === $dbData) {
165+
$this->options['expiry_field'] => ['$gte' => $this->getUTCDateTime()],
166+
], [
167+
'projection' => [
168+
'_id' => false,
169+
$this->options['data_field'] => true,
170+
],
171+
]));
172+
$dbData->setTypeMap(['root' => 'object']);
173+
$dbData->rewind();
174+
$data = $dbData->current();
175+
176+
if (!$data) {
147177
return '';
148178
}
149179

150-
return $dbData[$this->options['data_field']]->getData();
180+
return (string) $data->{$this->options['data_field']};
151181
}
152182

153-
private function getCollection(): Collection
183+
private function getUTCDateTime(int $additionalSeconds = 0): UTCDateTime
154184
{
155-
return $this->collection ??= $this->mongo->selectCollection($this->options['database'], $this->options['collection']);
156-
}
185+
$timestamp = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
157186

158-
protected function getMongo(): Client
159-
{
160-
return $this->mongo;
187+
return new UTCDateTime(($timestamp->getTimestamp() + $additionalSeconds) * 1000);
161188
}
162189
}

0 commit comments

Comments
 (0)
0