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