18
18
use Symfony \Component \Mailer \Bridge \Mailgun \Transport \MailgunTransportFactory ;
19
19
use Symfony \Component \Mailer \Bridge \Postmark \Transport \PostmarkTransportFactory ;
20
20
use Symfony \Component \Mailer \Bridge \Sendgrid \Transport \SendgridTransportFactory ;
21
+ use Symfony \Component \Mailer \Exception \InvalidArgumentException ;
21
22
use Symfony \Component \Mailer \Exception \UnsupportedHostException ;
22
23
use Symfony \Component \Mailer \Transport \Dsn ;
23
24
use Symfony \Component \Mailer \Transport \FailoverTransport ;
@@ -82,17 +83,54 @@ public function fromStrings(array $dsns): Transports
82
83
83
84
public function fromString (string $ dsn ): TransportInterface
84
85
{
85
- $ dsns = preg_split ( ' /\s++\|\|\s++/ ' , $ dsn );
86
- if (\count ( $ dsns ) > 1 ) {
87
- return new FailoverTransport ( $ this -> createFromDsns ( $ dsns ));
86
+ list ( $ transport , $ offset ) = $ this -> parseDsn ( $ dsn );
87
+ if ($ offset !== strlen ( $ dsn ) ) {
88
+ throw new InvalidArgumentException ( sprintf ( ' The DSN has some garbage at the end: %s. ' , substr ( $ dsn , $ offset ) ));
88
89
}
89
90
90
- $ dsns = preg_split ('/\s++&&\s++/ ' , $ dsn );
91
- if (\count ($ dsns ) > 1 ) {
92
- return new RoundRobinTransport ($ this ->createFromDsns ($ dsns ));
93
- }
91
+ return $ transport ;
92
+ }
93
+
94
+ private function parseDsn (string $ dsn , int $ offset = 0 ): array {
95
+ static $ maps = [
96
+ 'failover ' => FailoverTransport::class,
97
+ 'roundrobin ' => RoundRobinTransport::class,
98
+ ];
99
+
100
+ while (true ) {
101
+ foreach ($ maps as $ name => $ class ) {
102
+ $ name .= '( ' ;
103
+ if ($ name === substr ($ dsn , $ offset , strlen ($ name ))) {
104
+ $ offset += strlen ($ name ) - 1 ;
105
+ preg_match ('{\(([^()]|(?R))*\)}A ' , $ dsn , $ matches , 0 , $ offset );
106
+ if (!isset ($ matches [0 ])) {
107
+ continue ;
108
+ }
109
+
110
+ ++$ offset ;
111
+ $ args = [];
112
+ while (true ) {
113
+ list ($ arg , $ offset ) = $ this ->parseDsn ($ dsn , $ offset );
114
+ $ args [] = $ arg ;
115
+ if (strlen ($ dsn ) === $ offset ) {
116
+ break ;
117
+ }
118
+ ++$ offset ;
119
+ if (') ' === $ dsn [$ offset - 1 ]) {
120
+ break ;
121
+ }
122
+ }
123
+
124
+ return [new $ class ($ args ), $ offset ];
125
+ }
126
+ }
94
127
95
- return $ this ->fromDsnObject (Dsn::fromString ($ dsn ));
128
+ if ($ pos = strcspn ($ dsn , ' ) ' , $ offset )) {
129
+ return [$ this ->fromDsnObject (Dsn::fromString (substr ($ dsn , $ offset , $ pos ))), $ offset + $ pos ];
130
+ }
131
+
132
+ return [$ this ->fromDsnObject (Dsn::fromString (substr ($ dsn , $ offset ))), strlen ($ dsn )];
133
+ }
96
134
}
97
135
98
136
public function fromDsnObject (Dsn $ dsn ): TransportInterface
@@ -106,21 +144,6 @@ public function fromDsnObject(Dsn $dsn): TransportInterface
106
144
throw new UnsupportedHostException ($ dsn );
107
145
}
108
146
109
- /**
110
- * @param string[] $dsns
111
- *
112
- * @return TransportInterface[]
113
- */
114
- private function createFromDsns (array $ dsns ): array
115
- {
116
- $ transports = [];
117
- foreach ($ dsns as $ dsn ) {
118
- $ transports [] = $ this ->fromDsnObject (Dsn::fromString ($ dsn ));
119
- }
120
-
121
- return $ transports ;
122
- }
123
-
124
147
private static function getDefaultFactories (EventDispatcherInterface $ dispatcher = null , HttpClientInterface $ client = null , LoggerInterface $ logger = null ): iterable
125
148
{
126
149
foreach (self ::FACTORY_CLASSES as $ factoryClass ) {
0 commit comments