Skip to content

Commit 6350afa

Browse files
committed
[HttpFoundation] Add RedisSessionHandler (drop pipeline support)
1 parent 3c756bf commit 6350afa

File tree

1 file changed

+15
-134
lines changed

1 file changed

+15
-134
lines changed

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

Lines changed: 15 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111

1212
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
1313

14-
use Predis\Connection\Aggregate\ClusterInterface;
15-
use Predis\Response\Status;
14+
use Predis\Response\ErrorInterface;
1615

1716
/**
1817
* Redis based session storage handler based on the Redis class
@@ -39,24 +38,22 @@ class RedisSessionHandler extends AbstractSessionHandler
3938
* * prefix: The prefix to use for the keys in order to avoid collision
4039
* * expiretime: The time to live in seconds. Defaults to 1 day.
4140
*
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
4443
*
4544
* @throws \InvalidArgumentException When unsupported client or options are passed
4645
*/
47-
public function __construct($redis, ?array $options = null)
46+
public function __construct($redis, array $options = array())
4847
{
4948
if (!$redis instanceof \Redis && !$redis instanceof \RedisArray && !$redis instanceof \Predis\Client && !$redis instanceof RedisProxy) {
5049
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)));
5150
}
5251

5352
$this->redis = $redis;
54-
$options = (array) $options;
5553

5654
$diff = array_diff(array_keys($options), array('prefix', 'expiretime'));
5755
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)));
6057
}
6158

6259
$this->ttl = (int) ($options['expiretime'] ?? 86400);
@@ -68,30 +65,31 @@ public function __construct($redis, ?array $options = null)
6865
*/
6966
protected function doRead($sessionId): string
7067
{
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)) ?? '';
7669
}
7770

7871
/**
7972
* {@inheritdoc}
8073
*/
8174
protected function doWrite($sessionId, $data): bool
8275
{
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));
8577

86-
return empty($values);
78+
if (\is_bool($result)) {
79+
return $result;
80+
}
81+
82+
return !($result instanceof ErrorInterface);
8783
}
8884

8985
/**
9086
* {@inheritdoc}
9187
*/
9288
protected function doDestroy($sessionId): bool
9389
{
94-
return $this->doDelete(array($this->prefix.$sessionId));
90+
$this->redis->del($this->prefix.$sessionId);
91+
92+
return true;
9593
}
9694

9795
/**
@@ -117,121 +115,4 @@ public function updateTimestamp($sessionId, $data)
117115
{
118116
return $this->redis->expire($this->prefix.$sessionId, $this->ttl);
119117
}
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-
}
237118
}

0 commit comments

Comments
 (0)