@@ -9,12 +9,17 @@ class Dsn
99 /**
1010 * @var string
1111 */
12- private $ dsn ;
12+ private $ scheme ;
1313
1414 /**
1515 * @var string
1616 */
17- private $ scheme ;
17+ private $ schemeProtocol ;
18+
19+ /**
20+ * @var string[]
21+ */
22+ private $ schemeExtensions ;
1823
1924 /**
2025 * @var string|null
@@ -47,37 +52,43 @@ class Dsn
4752 private $ queryString ;
4853
4954 /**
50- * @var array
51- */
52- private $ query ;
53-
54- /**
55- * @var string
55+ * @var QueryBag
5656 */
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 );
7581 }
7682
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+ // }
8192
8293 public function getScheme (): string
8394 {
@@ -99,33 +110,21 @@ public function hasSchemeExtension(string $extension): bool
99110 return in_array ($ extension , $ this ->schemeExtensions , true );
100111 }
101112
102- /**
103- * @return null|string
104- */
105113 public function getUser (): ?string
106114 {
107115 return $ this ->user ;
108116 }
109117
110- /**
111- * @return null|string
112- */
113118 public function getPassword (): ?string
114119 {
115120 return $ this ->password ;
116121 }
117122
118- /**
119- * @return null|string
120- */
121123 public function getHost (): ?string
122124 {
123125 return $ this ->host ;
124126 }
125127
126- /**
127- * @return int|null
128- */
129128 public function getPort (): ?int
130129 {
131130 return $ this ->port ;
@@ -141,74 +140,44 @@ public function getQueryString(): ?string
141140 return $ this ->queryString ;
142141 }
143142
144- public function getQuery (): array
143+ public function getQueryBag (): QueryBag
145144 {
146- return $ this ->query ;
145+ return $ this ->queryBag ;
147146 }
148147
149- public function getQueryParameter ( string $ name , string $ default = null ): ? string
148+ public function getQuery ( ): array
150149 {
151- return array_key_exists ( $ name , $ this ->query ) ? $ this -> query [ $ name ] : $ default ;
150+ return $ this ->queryBag -> toArray () ;
152151 }
153152
154- public function getInt (string $ name , int $ default = null ): ?int
153+ public function getString (string $ name , string $ default = null ): ?string
155154 {
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+ }
164157
165- return (int ) $ value ;
158+ public function getDecimal (string $ name , int $ default = null ): ?int
159+ {
160+ return $ this ->queryBag ->getDecimal ($ name , $ default );
166161 }
167162
168163 public function getOctal (string $ name , int $ default = null ): ?int
169164 {
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 );
180166 }
181167
182168 public function getFloat (string $ name , float $ default = null ): ?float
183169 {
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 );
194171 }
195172
196173 public function getBool (string $ name , bool $ default = null ): ?bool
197174 {
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+ }
210177
211- throw InvalidQueryParameterTypeException::create ($ name , 'bool ' );
178+ public function getArray (string $ name , bool $ default = null ): QueryBag
179+ {
180+ return $ this ->queryBag ->getArray ($ name , $ default );
212181 }
213182
214183 public function toArray ()
@@ -223,11 +192,21 @@ public function toArray()
223192 'port ' => $ this ->port ,
224193 'path ' => $ this ->path ,
225194 'queryString ' => $ this ->queryString ,
226- 'query ' => $ this ->query ,
195+ 'query ' => $ this ->queryBag -> toArray () ,
227196 ];
228197 }
229198
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
231210 {
232211 if (false === strpos ($ dsn , ': ' )) {
233212 throw new \LogicException (sprintf ('The DSN is invalid. It does not have scheme separator ":". ' ));
@@ -241,43 +220,87 @@ private function parse(string $dsn): void
241220 }
242221
243222 $ schemeParts = explode ('+ ' , $ scheme );
244- $ this ->scheme = $ scheme ;
245- $ this ->schemeProtocol = $ schemeParts [0 ];
223+ $ schemeProtocol = $ schemeParts [0 ];
246224
247225 unset($ schemeParts [0 ]);
248- $ this -> schemeExtensions = array_values ($ schemeParts );
226+ $ schemeExtensions = array_values ($ schemeParts );
249227
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 ;
253230
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 );
256234 }
257235
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 );
260240 }
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+ ];
264268 }
265269
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 ];
269277
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+ }
272282
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+ );
274295 }
296+
297+ return $ dsns ;
275298 }
276299
277300 /**
278301 * based on http://php.net/manual/en/function.parse-str.php#119484 with some slight modifications.
279302 */
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
281304 {
282305 $ result = [];
283306 $ parts = explode ($ argSeparator , $ queryString );
0 commit comments