Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 52aeb75

Browse files
[Cache] Add DSN based Redis connection factory
1 parent b0a0829 commit 52aeb75

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

src/Symfony/Component/Cache/Adapter/RedisAdapter.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,89 @@
1818
*/
1919
class RedisAdapter extends AbstractAdapter
2020
{
21+
private static $defaultConnectionOptions = array(
22+
'class' => \Redis::class,
23+
'persistent' => 0,
24+
'timeout' => 0,
25+
'read_timeout' => 0,
26+
'retry_interval' => 0,
27+
);
2128
private $redis;
2229

2330
public function __construct(\Redis $redisConnection, $namespace = '', $defaultLifetime = 0)
2431
{
2532
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
2633
throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
2734
}
35+
if (!$redisConnection->isConnected()) {
36+
throw new InvalidArgumentException('Redis connection is not connected.');
37+
}
2838
$this->redis = $redisConnection;
2939

3040
parent::__construct($namespace, $defaultLifetime);
3141
}
3242

43+
/**
44+
* Creates a Redis connection using a DSN configuration.
45+
*
46+
* Example DNS:
47+
* - redis://localhost
48+
* - redis://example.com:1234
49+
* - redis://[email protected]/13
50+
* - redis:///var/run/redis.sock
51+
* - redis:///var/run/redis.sock?dbindex=13&user=secret
52+
*
53+
* @param string $dsn
54+
*
55+
* @throws InvalidArgumentException When the DSN is invalid.
56+
*
57+
* @return \Redis
58+
*/
59+
public static function createConnection($dsn, array $options = array())
60+
{
61+
if (0 !== strpos($dsn, 'redis://')) {
62+
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis://"', $dsn));
63+
}
64+
if (false === $params = parse_url(substr_replace($dsn, 'file', 0, 5))) {
65+
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn));
66+
}
67+
if (!isset($params['host']) && !isset($params['path'])) {
68+
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn));
69+
}
70+
if (isset($params['query'])) {
71+
parse_str($params['query'], $query);
72+
$params += $query;
73+
}
74+
$params += $options + self::$defaultConnectionOptions + array(
75+
'host' => isset($params['host']) ? $params['host'] : $params['path'],
76+
'port' => isset($params['host']) ? 6379 : null,
77+
'dbindex' => isset($params['host'], $params['path']) ? substr($params['path'], 1) : 0,
78+
'user' => '',
79+
);
80+
if (\Redis::class !== $params['class'] && !is_subclass_of($params['class'], \Redis::class)) {
81+
throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis"', $params['class']));
82+
}
83+
$connect = empty($params['persistent']) ? 'connect' : 'pconnect';
84+
$redis = new $params['class']();
85+
@$redis->{$connect}($params['host'], $params['port'], $params['timeout'], null, $params['retry_interval']);
86+
87+
if (@!$redis->isConnected()) {
88+
$e = ($e = error_get_last()) && preg_match('/^Redis::p?connect\(\): (.*)/', $e['message'], $e) ? sprintf(' (%s)', $e[1]) : '';
89+
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $e, $dsn));
90+
}
91+
92+
if (($params['user'] && !$redis->auth($params['user']))
93+
|| ($params['dbindex'] && !$redis->select($params['dbindex']))
94+
|| ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
95+
) {
96+
$e = preg_replace('/^ERR /', '', $redis->getLastError());
97+
$redis->close();
98+
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
99+
}
100+
101+
return $redis;
102+
}
103+
33104
/**
34105
* {@inheritdoc}
35106
*/

src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,63 @@ public static function tearDownAfterClass()
4444
self::$redis->flushDB();
4545
self::$redis->close();
4646
}
47+
48+
public function testCreateConnection()
49+
{
50+
$redis = RedisAdapter::createConnection('redis://localhost');
51+
$this->assertTrue($redis->isConnected());
52+
$this->assertSame(0, $redis->getDbNum());
53+
54+
$redis = RedisAdapter::createConnection('redis://localhost?dbindex=1');
55+
$this->assertSame(1, $redis->getDbNum());
56+
57+
$redis = RedisAdapter::createConnection('redis://localhost/2');
58+
$this->assertSame(2, $redis->getDbNum());
59+
60+
$redis = RedisAdapter::createConnection('redis://localhost', array('timeout' => 3));
61+
$this->assertEquals(3, $redis->getTimeout());
62+
63+
$redis = RedisAdapter::createConnection('redis://localhost?timeout=4');
64+
$this->assertEquals(4, $redis->getTimeout());
65+
66+
$redis = RedisAdapter::createConnection('redis://localhost', array('read_timeout' => 5));
67+
$this->assertEquals(5, $redis->getReadTimeout());
68+
}
69+
70+
/**
71+
* @dataProvider provideFailedCreateConnection
72+
* @expectedException Symfony\Component\Cache\Exception\InvalidArgumentException
73+
* @expectedExceptionMessage Redis connection failed
74+
*/
75+
public function testFailedCreateConnection($dsn)
76+
{
77+
RedisAdapter::createConnection($dsn);
78+
}
79+
80+
public function provideFailedCreateConnection()
81+
{
82+
return array(
83+
array('redis://localhost:1234'),
84+
array('redis://foo@localhost'),
85+
array('redis://localhost?dbindex=123'),
86+
);
87+
}
88+
89+
/**
90+
* @dataProvider provideInvalidCreateConnection
91+
* @expectedException Symfony\Component\Cache\Exception\InvalidArgumentException
92+
* @expectedExceptionMessage Invalid Redis DSN
93+
*/
94+
public function testInvalidCreateConnection($dsn)
95+
{
96+
RedisAdapter::createConnection($dsn);
97+
}
98+
99+
public function provideInvalidCreateConnection()
100+
{
101+
return array(
102+
array('foo://localhost'),
103+
array('redis://'),
104+
);
105+
}
47106
}

0 commit comments

Comments
 (0)