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

Skip to content

Commit 71f5d08

Browse files
committed
Reimplement Lock & Session using only ext-mongodb
1 parent 547485e commit 71f5d08

File tree

9 files changed

+287
-250
lines changed

9 files changed

+287
-250
lines changed

.github/workflows/integration-tests.yml

Lines changed: 0 additions & 1 deletion
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/Session/Storage/Handler/MongoDbSessionHandler.php

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,22 @@
1515
use MongoDB\BSON\UTCDateTime;
1616
use MongoDB\Client;
1717
use MongoDB\Collection;
18+
use MongoDB\Driver\BulkWrite;
19+
use MongoDB\Driver\Manager;
20+
use MongoDB\Driver\Query;
1821

1922
/**
20-
* Session handler using the mongodb/mongodb package and MongoDB driver extension.
23+
* Session handler using the MongoDB driver extension.
2124
*
2225
* @author Markus Bachmann <markus.bachmann@bachi.biz>
26+
* @author Jérôme Tamarelle <jerome@tamarelle.net>
2327
*
24-
* @see https://packagist.org/packages/mongodb/mongodb
2528
* @see https://php.net/mongodb
2629
*/
2730
class MongoDbSessionHandler extends AbstractSessionHandler
2831
{
29-
private Client $mongo;
30-
private Collection $collection;
32+
private Manager $manager;
33+
private string $namespace;
3134
private array $options;
3235
private int|\Closure|null $ttl;
3336

@@ -62,13 +65,18 @@ class MongoDbSessionHandler extends AbstractSessionHandler
6265
*
6366
* @throws \InvalidArgumentException When "database" or "collection" not provided
6467
*/
65-
public function __construct(Client $mongo, array $options)
68+
public function __construct(Client|Manager $mongo, array $options)
6669
{
6770
if (!isset($options['database']) || !isset($options['collection'])) {
6871
throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler.');
6972
}
7073

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

7381
$this->options = array_merge([
7482
'id_field' => '_id',
@@ -86,77 +94,92 @@ public function close(): bool
8694

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

93105
return true;
94106
}
95107

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

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

108124
$fields = [
109-
$this->options['time_field'] => new UTCDateTime(),
125+
$this->options['time_field'] => $this->getUTCDateTime(),
110126
$this->options['expiry_field'] => $expiry,
111127
$this->options['data_field'] => new Binary($data, Binary::TYPE_OLD_BINARY),
112128
];
113129

114-
$this->getCollection()->updateOne(
130+
$write = new BulkWrite();
131+
$write->update(
115132
[$this->options['id_field'] => $sessionId],
116133
['$set' => $fields],
117134
['upsert' => true]
118135
);
119136

137+
$this->manager->executeBulkWrite($this->namespace, $write);
138+
120139
return true;
121140
}
122141

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

128-
$this->getCollection()->updateOne(
147+
$write = new BulkWrite();
148+
$write->update(
129149
[$this->options['id_field'] => $sessionId],
130150
['$set' => [
131-
$this->options['time_field'] => new UTCDateTime(),
151+
$this->options['time_field'] => $this->getUTCDateTime(),
132152
$this->options['expiry_field'] => $expiry,
133-
]]
153+
]],
154+
['limit' => 1],
134155
);
135156

157+
$this->manager->executeBulkWrite($this->namespace, $write);
158+
136159
return true;
137160
}
138161

139162
protected function doRead(#[\SensitiveParameter] string $sessionId): string
140163
{
141-
$dbData = $this->getCollection()->findOne([
164+
$dbData = $this->manager->executeQuery($this->namespace, new Query([
142165
$this->options['id_field'] => $sessionId,
143-
$this->options['expiry_field'] => ['$gte' => new UTCDateTime()],
144-
]);
166+
$this->options['expiry_field'] => ['$gte' => $this->getUTCDateTime()],
167+
]));
168+
$dbData->setTypeMap(['root' => 'bson']);
169+
$dbData->rewind();
170+
$data = $dbData->current();
145171

146-
if (null === $dbData) {
172+
if (!$data) {
147173
return '';
148174
}
149175

150-
return $dbData[$this->options['data_field']]->getData();
176+
return $data->get($this->options['data_field']);
151177
}
152178

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

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

0 commit comments

Comments
 (0)
0