@@ -74,32 +74,19 @@ public function __construct(array $configuration, array $connectionCredentials =
74
74
$ auth = null ;
75
75
}
76
76
77
- $ initializer = static function ($ redis ) use ($ host , $ port , $ auth , $ serializer , $ dbIndex ) {
78
- if ($ redis instanceof \Redis) {
79
- $ redis ->connect ($ host , $ port );
80
- }
81
-
82
- $ redis ->setOption (\Redis::OPT_SERIALIZER , $ serializer );
83
-
84
- if (null !== $ auth && $ redis instanceof \Redis && !$ redis ->auth ($ auth )) {
85
- throw new InvalidArgumentException ('Redis connection failed: ' .$ redis ->getLastError ());
86
- }
87
-
88
- if ($ dbIndex && $ redis instanceof \Redis && !$ redis ->select ($ dbIndex )) {
89
- throw new InvalidArgumentException ('Redis connection failed: ' .$ redis ->getLastError ());
90
- }
91
-
92
- return true ;
93
- };
94
-
95
- if (null === $ redis ) {
96
- $ redis = new \Redis ();
97
- }
98
-
99
- if ($ configuration ['lazy ' ] ?? self ::DEFAULT_OPTIONS ['lazy ' ]) {
100
- $ redis = new RedisProxy ($ redis , $ initializer );
77
+ $ lazy = $ configuration ['lazy ' ] ?? self ::DEFAULT_OPTIONS ['lazy ' ];
78
+ if (\is_array ($ host ) || $ redis instanceof \RedisCluster) {
79
+ $ hosts = \is_string ($ host ) ? [$ host .': ' .$ port ] : $ host ; // Always ensure we have an array
80
+ $ initializer = static function ($ redis ) use ($ hosts , $ auth , $ serializer ) {
81
+ return self ::initializeRedisCluster ($ redis , $ hosts , $ auth , $ serializer );
82
+ };
83
+ $ redis = $ lazy ? new RedisClusterProxy ($ redis , $ initializer ) : $ initializer ($ redis );
101
84
} else {
102
- $ initializer ($ redis );
85
+ $ redis = $ redis ?? new \Redis ();
86
+ $ initializer = static function ($ redis ) use ($ host , $ port , $ auth , $ serializer , $ dbIndex ) {
87
+ return self ::initializeRedis ($ redis , $ host , $ port , $ auth , $ serializer , $ dbIndex );
88
+ };
89
+ $ redis = $ lazy ? new RedisProxy ($ redis , $ initializer ) : $ initializer ($ redis );
103
90
}
104
91
105
92
$ this ->connection = $ redis ;
@@ -122,21 +109,57 @@ public function __construct(array $configuration, array $connectionCredentials =
122
109
$ this ->claimInterval = $ configuration ['claim_interval ' ] ?? self ::DEFAULT_OPTIONS ['claim_interval ' ];
123
110
}
124
111
125
- public static function fromDsn ( string $ dsn , array $ redisOptions = [], \ Redis $ redis = null ): self
112
+ private static function initializeRedis ( \ Redis $ redis , string $ host , int $ port , ? string $ auth , int $ serializer , int $ dbIndex ): \ Redis
126
113
{
127
- $ url = $ dsn ;
128
- $ scheme = 0 === strpos ( $ dsn , ' rediss: ' ) ? ' rediss ' : ' redis ' ;
114
+ $ redis -> connect ( $ host , $ port ) ;
115
+ $ redis -> setOption (\Redis:: OPT_SERIALIZER , $ serializer ) ;
129
116
130
- if (preg_match ( ' #^ ' . $ scheme . ' :///([^:@])+$# ' , $ dsn )) {
131
- $ url = str_replace ( $ scheme . ' : ' , ' file: ' , $ dsn );
117
+ if (null !== $ auth && ! $ redis -> auth ( $ auth )) {
118
+ throw new InvalidArgumentException ( ' Redis connection failed: ' . $ redis -> getLastError () );
132
119
}
133
120
134
- if (false === $ parsedUrl = parse_url ( $ url )) {
135
- throw new InvalidArgumentException (sprintf ( ' The given Redis DSN "%s" is invalid. ' , $ dsn ));
121
+ if ($ dbIndex && ! $ redis -> select ( $ dbIndex )) {
122
+ throw new InvalidArgumentException (' Redis connection failed: ' . $ redis -> getLastError ( ));
136
123
}
137
- if (isset ($ parsedUrl ['query ' ])) {
138
- parse_str ($ parsedUrl ['query ' ], $ dsnOptions );
139
- $ redisOptions = array_merge ($ redisOptions , $ dsnOptions );
124
+
125
+ return $ redis ;
126
+ }
127
+
128
+ private static function initializeRedisCluster (?\RedisCluster $ redis , array $ hosts , ?string $ auth , int $ serializer ): \RedisCluster
129
+ {
130
+ if (null === $ redis ) {
131
+ $ redis = new \RedisCluster (null , $ hosts , 0.0 , 0.0 , false , $ auth );
132
+ }
133
+
134
+ $ redis ->setOption (\Redis::OPT_SERIALIZER , $ serializer );
135
+
136
+ return $ redis ;
137
+ }
138
+
139
+ /**
140
+ * @param \Redis|\RedisCluster|null $redis
141
+ */
142
+ public static function fromDsn (string $ dsn , array $ redisOptions = [], $ redis = null ): self
143
+ {
144
+ if (false === strpos ($ dsn , ', ' )) {
145
+ $ parsedUrl = self ::parseDsn ($ dsn , $ redisOptions );
146
+ } else {
147
+ $ dsns = explode (', ' , $ dsn );
148
+ $ parsedUrls = array_map (function ($ dsn ) use (&$ redisOptions ) {
149
+ return self ::parseDsn ($ dsn , $ redisOptions );
150
+ }, $ dsns );
151
+
152
+ // Merge all the URLs, the last one overrides the previous ones
153
+ $ parsedUrl = array_merge (...$ parsedUrls );
154
+
155
+ // Regroup all the hosts in an array interpretable by RedisCluster
156
+ $ parsedUrl ['host ' ] = array_map (function ($ parsedUrl , $ dsn ) {
157
+ if (!isset ($ parsedUrl ['host ' ])) {
158
+ throw new InvalidArgumentException (sprintf ('Missing host in DSN part "%s", it must be defined when using Redis Cluster. ' , $ dsn ));
159
+ }
160
+
161
+ return $ parsedUrl ['host ' ].': ' .($ parsedUrl ['port ' ] ?? 6379 );
162
+ }, $ parsedUrls , $ dsns );
140
163
}
141
164
142
165
self ::validateOptions ($ redisOptions );
@@ -171,7 +194,7 @@ public static function fromDsn(string $dsn, array $redisOptions = [], \Redis $re
171
194
unset($ redisOptions ['dbindex ' ]);
172
195
}
173
196
174
- $ tls = 'rediss ' === $ scheme ;
197
+ $ tls = 'rediss ' === $ parsedUrl [ ' scheme ' ] ;
175
198
if (\array_key_exists ('tls ' , $ redisOptions )) {
176
199
trigger_deprecation ('symfony/redis-messenger ' , '5.3 ' , 'Providing "tls" parameter is deprecated, use "rediss://" DSN scheme instead ' );
177
200
$ tls = filter_var ($ redisOptions ['tls ' ], \FILTER_VALIDATE_BOOLEAN );
@@ -229,6 +252,26 @@ public static function fromDsn(string $dsn, array $redisOptions = [], \Redis $re
229
252
return new self ($ configuration , $ connectionCredentials , $ redisOptions , $ redis );
230
253
}
231
254
255
+ private static function parseDsn (string $ dsn , array &$ redisOptions ): array
256
+ {
257
+ $ url = $ dsn ;
258
+ $ scheme = 0 === strpos ($ dsn , 'rediss: ' ) ? 'rediss ' : 'redis ' ;
259
+
260
+ if (preg_match ('#^ ' .$ scheme .':///([^:@])+$# ' , $ dsn )) {
261
+ $ url = str_replace ($ scheme .': ' , 'file: ' , $ dsn );
262
+ }
263
+
264
+ if (false === $ parsedUrl = parse_url ($ url )) {
265
+ throw new InvalidArgumentException (sprintf ('The given Redis DSN "%s" is invalid. ' , $ dsn ));
266
+ }
267
+ if (isset ($ parsedUrl ['query ' ])) {
268
+ parse_str ($ parsedUrl ['query ' ], $ dsnOptions );
269
+ $ redisOptions = array_merge ($ redisOptions , $ dsnOptions );
270
+ }
271
+
272
+ return $ parsedUrl ;
273
+ }
274
+
232
275
private static function validateOptions (array $ options ): void
233
276
{
234
277
$ availableOptions = array_keys (self ::DEFAULT_OPTIONS );
0 commit comments