15
15
use MongoDB \BSON \UTCDateTime ;
16
16
use MongoDB \Client ;
17
17
use MongoDB \Collection ;
18
+ use MongoDB \Driver \BulkWrite ;
19
+ use MongoDB \Driver \Manager ;
20
+ use MongoDB \Driver \Query ;
18
21
19
22
/**
20
- * Session handler using the mongodb/mongodb package and MongoDB driver extension.
23
+ * Session handler using the MongoDB driver extension.
21
24
*
22
25
* @author Markus Bachmann <markus.bachmann@bachi.biz>
26
+ * @author Jérôme Tamarelle <jerome@tamarelle.net>
23
27
*
24
- * @see https://packagist.org/packages/mongodb/mongodb
25
28
* @see https://php.net/mongodb
26
29
*/
27
30
class MongoDbSessionHandler extends AbstractSessionHandler
28
31
{
29
- private Client $ mongo ;
30
- private Collection $ collection ;
32
+ private Manager $ manager ;
33
+ private string $ namespace ;
31
34
private array $ options ;
32
35
private int |\Closure |null $ ttl ;
33
36
@@ -62,13 +65,18 @@ class MongoDbSessionHandler extends AbstractSessionHandler
62
65
*
63
66
* @throws \InvalidArgumentException When "database" or "collection" not provided
64
67
*/
65
- public function __construct (Client $ mongo , array $ options )
68
+ public function __construct (Client | Manager $ mongo , array $ options )
66
69
{
67
70
if (!isset ($ options ['database ' ]) || !isset ($ options ['collection ' ])) {
68
71
throw new \InvalidArgumentException ('You must provide the "database" and "collection" option for MongoDBSessionHandler. ' );
69
72
}
70
73
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 ' ];
72
80
73
81
$ this ->options = array_merge ([
74
82
'id_field ' => '_id ' ,
@@ -86,77 +94,92 @@ public function close(): bool
86
94
87
95
protected function doDestroy (#[\SensitiveParameter] string $ sessionId ): bool
88
96
{
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 );
92
104
93
105
return true ;
94
106
}
95
107
96
108
public function gc (int $ maxlifetime ): int |false
97
109
{
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 ;
101
117
}
102
118
103
119
protected function doWrite (#[\SensitiveParameter] string $ sessionId , string $ data ): bool
104
120
{
105
121
$ 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 );
107
123
108
124
$ fields = [
109
- $ this ->options ['time_field ' ] => new UTCDateTime (),
125
+ $ this ->options ['time_field ' ] => $ this -> getUTCDateTime (),
110
126
$ this ->options ['expiry_field ' ] => $ expiry ,
111
127
$ this ->options ['data_field ' ] => new Binary ($ data , Binary::TYPE_OLD_BINARY ),
112
128
];
113
129
114
- $ this ->getCollection ()->updateOne (
130
+ $ write = new BulkWrite ();
131
+ $ write ->update (
115
132
[$ this ->options ['id_field ' ] => $ sessionId ],
116
133
['$set ' => $ fields ],
117
134
['upsert ' => true ]
118
135
);
119
136
137
+ $ this ->manager ->executeBulkWrite ($ this ->namespace , $ write );
138
+
120
139
return true ;
121
140
}
122
141
123
142
public function updateTimestamp (#[\SensitiveParameter] string $ sessionId , string $ data ): bool
124
143
{
125
144
$ 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 );
127
146
128
- $ this ->getCollection ()->updateOne (
147
+ $ write = new BulkWrite ();
148
+ $ write ->update (
129
149
[$ this ->options ['id_field ' ] => $ sessionId ],
130
150
['$set ' => [
131
- $ this ->options ['time_field ' ] => new UTCDateTime (),
151
+ $ this ->options ['time_field ' ] => $ this -> getUTCDateTime (),
132
152
$ this ->options ['expiry_field ' ] => $ expiry ,
133
- ]]
153
+ ]],
154
+ ['limit ' => 1 ],
134
155
);
135
156
157
+ $ this ->manager ->executeBulkWrite ($ this ->namespace , $ write );
158
+
136
159
return true ;
137
160
}
138
161
139
162
protected function doRead (#[\SensitiveParameter] string $ sessionId ): string
140
163
{
141
- $ dbData = $ this ->getCollection ()-> findOne ([
164
+ $ dbData = $ this ->manager -> executeQuery ( $ this -> namespace , new Query ([
142
165
$ 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 ();
145
171
146
- if (null === $ dbData ) {
172
+ if (! $ data ) {
147
173
return '' ;
148
174
}
149
175
150
- return $ dbData [ $ this ->options ['data_field ' ]]-> getData ( );
176
+ return $ data -> get ( $ this ->options ['data_field ' ]);
151
177
}
152
178
153
- private function getCollection ( ): Collection
179
+ private function getUTCDateTime ( int $ additionalSeconds = 0 ): UTCDateTime
154
180
{
155
- return $ this ->collection ??= $ this ->mongo ->selectCollection ($ this ->options ['database ' ], $ this ->options ['collection ' ]);
156
- }
181
+ $ timestamp = (new \DateTimeImmutable ('now ' , new \DateTimeZone ('UTC ' )));
157
182
158
- protected function getMongo (): Client
159
- {
160
- return $ this ->mongo ;
183
+ return new UTCDateTime (($ timestamp ->getTimestamp () + $ additionalSeconds ) * 1000 );
161
184
}
162
185
}
0 commit comments