11
11
12
12
namespace Symfony \Component \HttpFoundation \Session \Storage \Handler ;
13
13
14
- use Predis \Connection \Aggregate \ClusterInterface ;
15
- use Predis \Response \Status ;
14
+ use Predis \Response \ErrorInterface ;
16
15
17
16
/**
18
17
* Redis based session storage handler based on the Redis class
@@ -39,24 +38,22 @@ class RedisSessionHandler extends AbstractSessionHandler
39
38
* * prefix: The prefix to use for the keys in order to avoid collision
40
39
* * expiretime: The time to live in seconds. Defaults to 1 day.
41
40
*
42
- * @param @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
43
- * @param null|array $options An associative array of options
41
+ * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redis
42
+ * @param null|array $options An associative array of options
44
43
*
45
44
* @throws \InvalidArgumentException When unsupported client or options are passed
46
45
*/
47
- public function __construct ($ redis , ? array $ options = null )
46
+ public function __construct ($ redis , array $ options = array () )
48
47
{
49
48
if (!$ redis instanceof \Redis && !$ redis instanceof \RedisArray && !$ redis instanceof \Predis \Client && !$ redis instanceof RedisProxy) {
50
49
throw new \InvalidArgumentException (\sprintf ('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given ' , __METHOD__ , \is_object ($ redis ) ? \get_class ($ redis ) : \gettype ($ redis )));
51
50
}
52
51
53
52
$ this ->redis = $ redis ;
54
- $ options = (array ) $ options ;
55
53
56
54
$ diff = array_diff (array_keys ($ options ), array ('prefix ' , 'expiretime ' ));
57
55
if ($ diff ) {
58
- $ exception = sprintf ('The following options are not supported "%s" ' , implode (', ' , $ diff ));
59
- throw new \InvalidArgumentException ($ exception );
56
+ throw new \InvalidArgumentException (sprintf ('The following options are not supported "%s" ' , implode (', ' , $ diff )));
60
57
}
61
58
62
59
$ this ->ttl = (int ) ($ options ['expiretime ' ] ?? 86400 );
@@ -68,30 +65,31 @@ public function __construct($redis, ?array $options = null)
68
65
*/
69
66
protected function doRead ($ sessionId ): string
70
67
{
71
- $ values = $ this ->doFetch (array ($ this ->prefix .$ sessionId ));
72
-
73
- foreach ($ values as $ value ) {
74
- return $ value ?: '' ;
75
- }
68
+ return \unserialize ($ this ->redis ->get ($ this ->prefix .$ sessionId )) ?? '' ;
76
69
}
77
70
78
71
/**
79
72
* {@inheritdoc}
80
73
*/
81
74
protected function doWrite ($ sessionId , $ data ): bool
82
75
{
83
- // will return failed saves (if empty, nothing failed)
84
- $ values = $ this ->doSave (array ($ this ->prefix .$ sessionId => $ data ), $ this ->ttl );
76
+ $ result = $ this ->redis ->setEx ($ this ->prefix .$ sessionId , $ this ->ttl , \serialize ($ data ));
85
77
86
- return empty ($ values );
78
+ if (\is_bool ($ result )) {
79
+ return $ result ;
80
+ }
81
+
82
+ return !($ result instanceof ErrorInterface);
87
83
}
88
84
89
85
/**
90
86
* {@inheritdoc}
91
87
*/
92
88
protected function doDestroy ($ sessionId ): bool
93
89
{
94
- return $ this ->doDelete (array ($ this ->prefix .$ sessionId ));
90
+ $ this ->redis ->del ($ this ->prefix .$ sessionId );
91
+
92
+ return true ;
95
93
}
96
94
97
95
/**
@@ -117,121 +115,4 @@ public function updateTimestamp($sessionId, $data)
117
115
{
118
116
return $ this ->redis ->expire ($ this ->prefix .$ sessionId , $ this ->ttl );
119
117
}
120
-
121
- /*
122
- * Note:
123
- * What follows is a direct inline of Cache component's RedisTrait functionality.
124
- * Wish we could just use the trait here instead. :\
125
- */
126
-
127
- private function doFetch (array $ ids )
128
- {
129
- if ($ ids ) {
130
- $ values = $ this ->pipeline (function () use ($ ids ) {
131
- foreach ($ ids as $ id ) {
132
- yield 'get ' => array ($ id );
133
- }
134
- });
135
- foreach ($ values as $ id => $ v ) {
136
- if ($ v ) {
137
- yield $ id => \unserialize ($ v );
138
- }
139
- }
140
- }
141
- }
142
-
143
- private function doDelete (array $ ids )
144
- {
145
- if ($ ids ) {
146
- $ this ->redis ->del ($ ids );
147
- }
148
-
149
- return true ;
150
- }
151
-
152
- private function doSave (array $ values , $ lifetime )
153
- {
154
- $ serialized = array ();
155
- $ failed = array ();
156
-
157
- foreach ($ values as $ id => $ value ) {
158
- try {
159
- $ serialized [$ id ] = \serialize ($ value );
160
- } catch (\Exception $ e ) {
161
- $ failed [] = $ id ;
162
- }
163
- }
164
-
165
- if (!$ serialized ) {
166
- return $ failed ;
167
- }
168
-
169
- $ results = $ this ->pipeline (function () use ($ serialized , $ lifetime ) {
170
- foreach ($ serialized as $ id => $ value ) {
171
- if (0 >= $ lifetime ) {
172
- yield 'set ' => array ($ id , $ value );
173
- } else {
174
- yield 'setEx ' => array ($ id , $ lifetime , $ value );
175
- }
176
- }
177
- });
178
- foreach ($ results as $ id => $ result ) {
179
- if (true !== $ result && (!$ result instanceof Status || $ result !== Status::get ('OK ' ))) {
180
- $ failed [] = $ id ;
181
- }
182
- }
183
-
184
- return $ failed ;
185
- }
186
-
187
- private function pipeline (\Closure $ generator )
188
- {
189
- $ ids = array ();
190
-
191
- if ($ this ->redis instanceof \Predis \Client && !$ this ->redis ->getConnection () instanceof ClusterInterface) {
192
- $ results = $ this ->redis ->pipeline (function ($ redis ) use ($ generator , &$ ids ) {
193
- foreach ($ generator () as $ command => $ args ) {
194
- call_user_func_array (array ($ redis , $ command ), $ args );
195
- $ ids [] = $ args [0 ];
196
- }
197
- });
198
- } elseif ($ this ->redis instanceof \RedisArray) {
199
- $ connections = $ results = $ ids = array ();
200
- foreach ($ generator () as $ command => $ args ) {
201
- if (!isset ($ connections [$ h = $ this ->redis ->_target ($ args [0 ])])) {
202
- $ connections [$ h ] = array ($ this ->redis ->_instance ($ h ), -1 );
203
- $ connections [$ h ][0 ]->multi (\Redis::PIPELINE );
204
- }
205
- call_user_func_array (array ($ connections [$ h ][0 ], $ command ), $ args );
206
- $ results [] = array ($ h , ++$ connections [$ h ][1 ]);
207
- $ ids [] = $ args [0 ];
208
- }
209
- foreach ($ connections as $ h => $ c ) {
210
- $ connections [$ h ] = $ c [0 ]->exec ();
211
- }
212
- foreach ($ results as $ k => list ($ h , $ c )) {
213
- $ results [$ k ] = $ connections [$ h ][$ c ];
214
- }
215
- } elseif ($ this ->redis instanceof \RedisCluster || ($ this ->redis instanceof \Predis \Client && $ this ->redis ->getConnection () instanceof ClusterInterface)) {
216
- // phpredis & predis don't support pipelining with RedisCluster
217
- // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
218
- // see https://github.com/nrk/predis/issues/267#issuecomment-123781423
219
- $ results = array ();
220
- foreach ($ generator () as $ command => $ args ) {
221
- $ results [] = call_user_func_array (array ($ this ->redis , $ command ), $ args );
222
- $ ids [] = $ args [0 ];
223
- }
224
- } else {
225
- $ this ->redis ->multi (\Redis::PIPELINE );
226
- foreach ($ generator () as $ command => $ args ) {
227
- call_user_func_array (array ($ this ->redis , $ command ), $ args );
228
- $ ids [] = $ args [0 ];
229
- }
230
- $ results = $ this ->redis ->exec ();
231
- }
232
-
233
- foreach ($ ids as $ k => $ id ) {
234
- yield $ id => $ results [$ k ];
235
- }
236
- }
237
118
}
0 commit comments