18
18
*/
19
19
class RedisAdapter extends AbstractAdapter
20
20
{
21
+ private static $ defaultConnectionOptions = array (
22
+ 'class ' => \Redis::class,
23
+ 'persistent ' => 0 ,
24
+ 'timeout ' => 0 ,
25
+ 'read_timeout ' => 0 ,
26
+ 'retry_interval ' => 0 ,
27
+ );
21
28
private $ redis ;
22
29
23
30
public function __construct (\Redis $ redisConnection , $ namespace = '' , $ defaultLifetime = 0 )
@@ -30,6 +37,80 @@ public function __construct(\Redis $redisConnection, $namespace = '', $defaultLi
30
37
parent ::__construct ($ namespace , $ defaultLifetime );
31
38
}
32
39
40
+ /**
41
+ * Creates a Redis connection using a DSN configuration.
42
+ *
43
+ * Example DSN:
44
+ * - redis://localhost
45
+ * - redis://example.com:1234
46
+ * - redis://secret@example.com/13
47
+ * - redis:///var/run/redis.sock
48
+ * - redis://secret@/var/run/redis.sock/13
49
+ *
50
+ * @param string $dsn
51
+ * @param array $options See self::$defaultConnectionOptions
52
+ *
53
+ * @throws InvalidArgumentException When the DSN is invalid.
54
+ *
55
+ * @return \Redis
56
+ */
57
+ public static function createConnection ($ dsn , array $ options = array ())
58
+ {
59
+ if (0 !== strpos ($ dsn , 'redis:// ' )) {
60
+ throw new InvalidArgumentException (sprintf ('Invalid Redis DSN: %s does not start with "redis://" ' , $ dsn ));
61
+ }
62
+ $ params = preg_replace_callback ('#^redis://(?:([^@]*)@)?# ' , function ($ m ) use (&$ auth ) {
63
+ if (isset ($ m [1 ])) {
64
+ $ auth = $ m [1 ];
65
+ }
66
+
67
+ return 'file:// ' ;
68
+ }, $ dsn );
69
+ if (false === $ params = parse_url ($ params )) {
70
+ throw new InvalidArgumentException (sprintf ('Invalid Redis DSN: %s ' , $ dsn ));
71
+ }
72
+ if (!isset ($ params ['host ' ]) && !isset ($ params ['path ' ])) {
73
+ throw new InvalidArgumentException (sprintf ('Invalid Redis DSN: %s ' , $ dsn ));
74
+ }
75
+ if (isset ($ params ['path ' ]) && preg_match ('#/(\d+)$# ' , $ params ['path ' ], $ m )) {
76
+ $ params ['dbindex ' ] = $ m [1 ];
77
+ $ params ['path ' ] = substr ($ params ['path ' ], 0 , -strlen ($ m [0 ]));
78
+ }
79
+ $ params += array (
80
+ 'host ' => isset ($ params ['host ' ]) ? $ params ['host ' ] : $ params ['path ' ],
81
+ 'port ' => isset ($ params ['host ' ]) ? 6379 : null ,
82
+ 'dbindex ' => 0 ,
83
+ );
84
+ if (isset ($ params ['query ' ])) {
85
+ parse_str ($ params ['query ' ], $ query );
86
+ $ params += $ query ;
87
+ }
88
+ $ params += $ options + self ::$ defaultConnectionOptions ;
89
+
90
+ if (\Redis::class !== $ params ['class ' ] && !is_subclass_of ($ params ['class ' ], \Redis::class)) {
91
+ throw new InvalidArgumentException (sprintf ('"%s" is not a subclass of "Redis" ' , $ params ['class ' ]));
92
+ }
93
+ $ connect = empty ($ params ['persistent ' ]) ? 'connect ' : 'pconnect ' ;
94
+ $ redis = new $ params ['class ' ]();
95
+ @$ redis ->{$ connect }($ params ['host ' ], $ params ['port ' ], $ params ['timeout ' ], null , $ params ['retry_interval ' ]);
96
+
97
+ if (@!$ redis ->isConnected ()) {
98
+ $ e = ($ e = error_get_last ()) && preg_match ('/^Redis::p?connect\(\): (.*)/ ' , $ e ['message ' ], $ e ) ? sprintf (' (%s) ' , $ e [1 ]) : '' ;
99
+ throw new InvalidArgumentException (sprintf ('Redis connection failed%s: %s ' , $ e , $ dsn ));
100
+ }
101
+
102
+ if ((null !== $ auth && !$ redis ->auth ($ auth ))
103
+ || ($ params ['dbindex ' ] && !$ redis ->select ($ params ['dbindex ' ]))
104
+ || ($ params ['read_timeout ' ] && !$ redis ->setOption (\Redis::OPT_READ_TIMEOUT , $ params ['read_timeout ' ]))
105
+ ) {
106
+ $ e = preg_replace ('/^ERR / ' , '' , $ redis ->getLastError ());
107
+ $ redis ->close ();
108
+ throw new InvalidArgumentException (sprintf ('Redis connection failed (%s): %s ' , $ e , $ dsn ));
109
+ }
110
+
111
+ return $ redis ;
112
+ }
113
+
33
114
/**
34
115
* {@inheritdoc}
35
116
*/
0 commit comments