Skip to content

Commit aec11ea

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

File tree

3 files changed

+66
-25
lines changed

3 files changed

+66
-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: 47 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,55 @@ 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+
{
96+
static $maps = [
97+
'failover' => FailoverTransport::class,
98+
'roundrobin' => RoundRobinTransport::class,
99+
];
100+
101+
while (true) {
102+
foreach ($maps as $name => $class) {
103+
$name .= '(';
104+
if ($name === substr($dsn, $offset, \strlen($name))) {
105+
$offset += \strlen($name) - 1;
106+
preg_match('{\(([^()]|(?R))*\)}A', $dsn, $matches, 0, $offset);
107+
if (!isset($matches[0])) {
108+
continue;
109+
}
110+
111+
++$offset;
112+
$args = [];
113+
while (true) {
114+
list($arg, $offset) = $this->parseDsn($dsn, $offset);
115+
$args[] = $arg;
116+
if (\strlen($dsn) === $offset) {
117+
break;
118+
}
119+
++$offset;
120+
if (')' === $dsn[$offset - 1]) {
121+
break;
122+
}
123+
}
124+
125+
return [new $class($args), $offset];
126+
}
127+
}
128+
129+
if ($pos = strcspn($dsn, ' )', $offset)) {
130+
return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset, $pos))), $offset + $pos];
131+
}
94132

95-
return $this->fromDsnObject(Dsn::fromString($dsn));
133+
return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset))), \strlen($dsn)];
134+
}
96135
}
97136

98137
public function fromDsnObject(Dsn $dsn): TransportInterface
@@ -106,21 +145,6 @@ public function fromDsnObject(Dsn $dsn): TransportInterface
106145
throw new UnsupportedHostException($dsn);
107146
}
108147

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-
124148
private static function getDefaultFactories(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): iterable
125149
{
126150
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