Skip to content

Commit b026b86

Browse files
committed
[Mailer] Change the syntax for DSNs using failover or roundrobin
1 parent dc376f5 commit b026b86

File tree

3 files changed

+65
-25
lines changed

3 files changed

+65
-25
lines changed

src/Symfony/Component/Mailer/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ CHANGELOG
44
4.4.0
55
-----
66

7+
* [BC BREAK] changed the syntax for failover and roundrobin DSNs
8+
9+
Before:
10+
11+
dummy://a || dummy://b (for failover)
12+
dummy://a && dummy://b (for roundrobin)
13+
14+
After:
15+
16+
failover(dummy://a dummy://b)
17+
roundrobin(dummy://a dummy://b)
18+
719
* added support for multiple transports on a `Mailer` instance
820
* [BC BREAK] removed the `auth_mode` DSN option (it is now always determined automatically)
921
* STARTTLS cannot be enabled anymore (it is used automatically if TLS is disabled and the server supports STARTTLS)

src/Symfony/Component/Mailer/Tests/TransportTest.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,19 @@ public function fromStringProvider(): iterable
4444
];
4545

4646
yield 'failover transport' => [
47-
'dummy://a || dummy://b',
47+
'failover(dummy://a dummy://b)',
4848
new FailoverTransport([$transportA, $transportB]),
4949
];
5050

5151
yield 'round robin transport' => [
52-
'dummy://a && dummy://b',
52+
'roundrobin(dummy://a dummy://b)',
5353
new RoundRobinTransport([$transportA, $transportB]),
5454
];
55+
56+
yield 'mixed transport' => [
57+
'roundrobin(dummy://a failover(dummy://b dummy://a) dummy://b)',
58+
new RoundRobinTransport([$transportA, new FailoverTransport([$transportB, $transportA]), $transportB]),
59+
];
5560
}
5661
}
5762

src/Symfony/Component/Mailer/Transport.php

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory;
1919
use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory;
2020
use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory;
21+
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
2122
use Symfony\Component\Mailer\Exception\UnsupportedHostException;
2223
use Symfony\Component\Mailer\Transport\Dsn;
2324
use Symfony\Component\Mailer\Transport\FailoverTransport;
@@ -82,17 +83,54 @@ public function fromStrings(array $dsns): Transports
8283

8384
public function fromString(string $dsn): TransportInterface
8485
{
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)));
8889
}
8990

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+
}
94127

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+
}
96134
}
97135

98136
public function fromDsnObject(Dsn $dsn): TransportInterface
@@ -106,21 +144,6 @@ public function fromDsnObject(Dsn $dsn): TransportInterface
106144
throw new UnsupportedHostException($dsn);
107145
}
108146

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-
124147
private static function getDefaultFactories(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): iterable
125148
{
126149
foreach (self::FACTORY_CLASSES as $factoryClass) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy