@@ -9,12 +9,17 @@ class Dsn
9
9
/**
10
10
* @var string
11
11
*/
12
- private $ dsn ;
12
+ private $ scheme ;
13
13
14
14
/**
15
15
* @var string
16
16
*/
17
- private $ scheme ;
17
+ private $ schemeProtocol ;
18
+
19
+ /**
20
+ * @var string[]
21
+ */
22
+ private $ schemeExtensions ;
18
23
19
24
/**
20
25
* @var string|null
@@ -47,37 +52,43 @@ class Dsn
47
52
private $ queryString ;
48
53
49
54
/**
50
- * @var array
51
- */
52
- private $ query ;
53
-
54
- /**
55
- * @var string
55
+ * @var QueryBag
56
56
*/
57
- private $ schemeProtocol ;
58
-
59
- /**
60
- * @var string[]
61
- */
62
- private $ schemeExtensions ;
63
-
64
- public function __construct (string $ dsn )
65
- {
66
- $ this ->dsn = $ dsn ;
67
- $ this ->query = [];
68
-
69
- $ this ->parse ($ dsn );
70
- }
71
-
72
- public function __toString (): string
73
- {
74
- return $ this ->dsn ;
57
+ private $ queryBag ;
58
+
59
+ public function __construct (
60
+ string $ scheme ,
61
+ string $ schemeProtocol ,
62
+ array $ schemeExtensions ,
63
+ ?string $ user ,
64
+ ?string $ password ,
65
+ ?string $ host ,
66
+ ?int $ port ,
67
+ ?string $ path ,
68
+ ?string $ queryString ,
69
+ array $ query
70
+ ) {
71
+ $ this ->scheme = $ scheme ;
72
+ $ this ->schemeProtocol = $ schemeProtocol ;
73
+ $ this ->schemeExtensions = $ schemeExtensions ;
74
+ $ this ->user = $ user ;
75
+ $ this ->password = $ password ;
76
+ $ this ->host = $ host ;
77
+ $ this ->port = $ port ;
78
+ $ this ->path = $ path ;
79
+ $ this ->queryString = $ queryString ;
80
+ $ this ->queryBag = new QueryBag ($ query );
75
81
}
76
82
77
- public function getDsn (): string
78
- {
79
- return $ this ->dsn ;
80
- }
83
+ // public function __toString(): string
84
+ // {
85
+ // return $this->dsn;
86
+ // }
87
+ //
88
+ // public function getDsn(): string
89
+ // {
90
+ // return $this->dsn;
91
+ // }
81
92
82
93
public function getScheme (): string
83
94
{
@@ -99,33 +110,21 @@ public function hasSchemeExtension(string $extension): bool
99
110
return in_array ($ extension , $ this ->schemeExtensions , true );
100
111
}
101
112
102
- /**
103
- * @return null|string
104
- */
105
113
public function getUser (): ?string
106
114
{
107
115
return $ this ->user ;
108
116
}
109
117
110
- /**
111
- * @return null|string
112
- */
113
118
public function getPassword (): ?string
114
119
{
115
120
return $ this ->password ;
116
121
}
117
122
118
- /**
119
- * @return null|string
120
- */
121
123
public function getHost (): ?string
122
124
{
123
125
return $ this ->host ;
124
126
}
125
127
126
- /**
127
- * @return int|null
128
- */
129
128
public function getPort (): ?int
130
129
{
131
130
return $ this ->port ;
@@ -141,74 +140,44 @@ public function getQueryString(): ?string
141
140
return $ this ->queryString ;
142
141
}
143
142
144
- public function getQuery (): array
143
+ public function getQueryBag (): QueryBag
145
144
{
146
- return $ this ->query ;
145
+ return $ this ->queryBag ;
147
146
}
148
147
149
- public function getQueryParameter ( string $ name , string $ default = null ): ? string
148
+ public function getQuery ( ): array
150
149
{
151
- return array_key_exists ( $ name , $ this ->query ) ? $ this -> query [ $ name ] : $ default ;
150
+ return $ this ->queryBag -> toArray () ;
152
151
}
153
152
154
- public function getInt (string $ name , int $ default = null ): ?int
153
+ public function getString (string $ name , string $ default = null ): ?string
155
154
{
156
- $ value = $ this ->getQueryParameter ($ name );
157
- if (null === $ value ) {
158
- return $ default ;
159
- }
160
-
161
- if (false == preg_match ('/^[\+\-]?[0-9]*$/ ' , $ value )) {
162
- throw InvalidQueryParameterTypeException::create ($ name , 'integer ' );
163
- }
155
+ return $ this ->queryBag ->getString ($ name , $ default );
156
+ }
164
157
165
- return (int ) $ value ;
158
+ public function getDecimal (string $ name , int $ default = null ): ?int
159
+ {
160
+ return $ this ->queryBag ->getDecimal ($ name , $ default );
166
161
}
167
162
168
163
public function getOctal (string $ name , int $ default = null ): ?int
169
164
{
170
- $ value = $ this ->getQueryParameter ($ name );
171
- if (null === $ value ) {
172
- return $ default ;
173
- }
174
-
175
- if (false == preg_match ('/^0[\+\-]?[0-7]*$/ ' , $ value )) {
176
- throw InvalidQueryParameterTypeException::create ($ name , 'integer ' );
177
- }
178
-
179
- return intval ($ value , 8 );
165
+ return $ this ->queryBag ->getOctal ($ name , $ default );
180
166
}
181
167
182
168
public function getFloat (string $ name , float $ default = null ): ?float
183
169
{
184
- $ value = $ this ->getQueryParameter ($ name );
185
- if (null === $ value ) {
186
- return $ default ;
187
- }
188
-
189
- if (false == is_numeric ($ value )) {
190
- throw InvalidQueryParameterTypeException::create ($ name , 'float ' );
191
- }
192
-
193
- return (float ) $ value ;
170
+ return $ this ->queryBag ->getFloat ($ name , $ default );
194
171
}
195
172
196
173
public function getBool (string $ name , bool $ default = null ): ?bool
197
174
{
198
- $ value = $ this ->getQueryParameter ($ name );
199
- if (null === $ value ) {
200
- return $ default ;
201
- }
202
-
203
- if (in_array ($ value , ['' , '0 ' , 'false ' ], true )) {
204
- return false ;
205
- }
206
-
207
- if (in_array ($ value , ['1 ' , 'true ' ], true )) {
208
- return true ;
209
- }
175
+ return $ this ->queryBag ->getBool ($ name , $ default );
176
+ }
210
177
211
- throw InvalidQueryParameterTypeException::create ($ name , 'bool ' );
178
+ public function getArray (string $ name , bool $ default = null ): QueryBag
179
+ {
180
+ return $ this ->queryBag ->getArray ($ name , $ default );
212
181
}
213
182
214
183
public function toArray ()
@@ -223,11 +192,21 @@ public function toArray()
223
192
'port ' => $ this ->port ,
224
193
'path ' => $ this ->path ,
225
194
'queryString ' => $ this ->queryString ,
226
- 'query ' => $ this ->query ,
195
+ 'query ' => $ this ->queryBag -> toArray () ,
227
196
];
228
197
}
229
198
230
- private function parse (string $ dsn ): void
199
+ public static function parseFirst (string $ dsn ): ?self
200
+ {
201
+ return self ::parse ($ dsn )[0 ];
202
+ }
203
+
204
+ /**
205
+ * @param string $dsn
206
+ *
207
+ * @return Dsn[]
208
+ */
209
+ public static function parse (string $ dsn ): array
231
210
{
232
211
if (false === strpos ($ dsn , ': ' )) {
233
212
throw new \LogicException (sprintf ('The DSN is invalid. It does not have scheme separator ":". ' ));
@@ -241,43 +220,87 @@ private function parse(string $dsn): void
241
220
}
242
221
243
222
$ schemeParts = explode ('+ ' , $ scheme );
244
- $ this ->scheme = $ scheme ;
245
- $ this ->schemeProtocol = $ schemeParts [0 ];
223
+ $ schemeProtocol = $ schemeParts [0 ];
246
224
247
225
unset($ schemeParts [0 ]);
248
- $ this -> schemeExtensions = array_values ($ schemeParts );
226
+ $ schemeExtensions = array_values ($ schemeParts );
249
227
250
- if ($ host = parse_url ($ dsn , PHP_URL_HOST )) {
251
- $ this ->host = $ host ;
252
- }
228
+ $ user = parse_url ($ dsn , PHP_URL_USER ) ?: null ;
229
+ $ password = parse_url ($ dsn , PHP_URL_PASS ) ?: null ;
253
230
254
- if ($ port = parse_url ($ dsn , PHP_URL_PORT )) {
255
- $ this ->port = (int ) $ port ;
231
+ $ path = parse_url ($ dsn , PHP_URL_PATH ) ?: null ;
232
+ if ($ path ) {
233
+ $ path = rawurldecode ($ path );
256
234
}
257
235
258
- if ($ user = parse_url ($ dsn , PHP_URL_USER )) {
259
- $ this ->user = $ user ;
236
+ $ query = [];
237
+ $ queryString = parse_url ($ dsn , PHP_URL_QUERY ) ?: null ;
238
+ if (is_string ($ queryString )) {
239
+ $ query = self ::httpParseQuery ($ queryString , '& ' , PHP_QUERY_RFC3986 );
260
240
}
261
-
262
- if ($ password = parse_url ($ dsn , PHP_URL_PASS )) {
263
- $ this ->password = $ password ;
241
+ $ hostsPorts = '' ;
242
+ if (0 === strpos ($ dsnWithoutScheme , '// ' )) {
243
+ $ dsnWithoutScheme = substr ($ dsnWithoutScheme , 2 );
244
+ $ dsnWithoutUserPassword = explode ('@ ' , $ dsnWithoutScheme , 2 );
245
+ $ dsnWithoutUserPassword = 2 === count ($ dsnWithoutUserPassword ) ?
246
+ $ dsnWithoutUserPassword [1 ] :
247
+ $ dsnWithoutUserPassword [0 ]
248
+ ;
249
+
250
+ list ($ hostsPorts ) = explode ('# ' , $ dsnWithoutUserPassword , 2 );
251
+ list ($ hostsPorts ) = explode ('? ' , $ hostsPorts , 2 );
252
+ list ($ hostsPorts ) = explode ('/ ' , $ hostsPorts , 2 );
253
+ } else {
254
+ return [
255
+ new self (
256
+ $ scheme ,
257
+ $ schemeProtocol ,
258
+ $ schemeExtensions ,
259
+ null ,
260
+ null ,
261
+ null ,
262
+ null ,
263
+ $ path ,
264
+ $ queryString ,
265
+ $ query
266
+ ),
267
+ ];
264
268
}
265
269
266
- if ($ path = parse_url ($ dsn , PHP_URL_PATH )) {
267
- $ this ->path = rawurldecode ($ path );
268
- }
270
+ $ dsns = [];
271
+ $ hostParts = explode (', ' , $ hostsPorts );
272
+ foreach ($ hostParts as $ key => $ hostPart ) {
273
+ unset($ hostParts [$ key ]);
274
+
275
+ $ parts = explode (': ' , $ hostPart , 2 );
276
+ $ host = $ parts [0 ];
269
277
270
- if ($ queryString = parse_url ($ dsn , PHP_URL_QUERY )) {
271
- $ this ->queryString = $ queryString ;
278
+ $ port = null ;
279
+ if (isset ($ parts [1 ])) {
280
+ $ port = (int ) $ parts [1 ];
281
+ }
272
282
273
- $ this ->query = $ this ->httpParseQuery ($ queryString , '& ' , PHP_QUERY_RFC3986 );
283
+ $ dsns [] = new self (
284
+ $ scheme ,
285
+ $ schemeProtocol ,
286
+ $ schemeExtensions ,
287
+ $ user ,
288
+ $ password ,
289
+ $ host ,
290
+ $ port ,
291
+ $ path ,
292
+ $ queryString ,
293
+ $ query
294
+ );
274
295
}
296
+
297
+ return $ dsns ;
275
298
}
276
299
277
300
/**
278
301
* based on http://php.net/manual/en/function.parse-str.php#119484 with some slight modifications.
279
302
*/
280
- private function httpParseQuery (string $ queryString , string $ argSeparator = '& ' , int $ decType = PHP_QUERY_RFC1738 ): array
303
+ private static function httpParseQuery (string $ queryString , string $ argSeparator = '& ' , int $ decType = PHP_QUERY_RFC1738 ): array
281
304
{
282
305
$ result = [];
283
306
$ parts = explode ($ argSeparator , $ queryString );
0 commit comments