Skip to content

Commit 5b9cded

Browse files
committed
Add transport factories (closes #31385, closes #32523)
1 parent af309b0 commit 5b9cded

32 files changed

+1660
-467
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@
7777
use Symfony\Component\Lock\Store\FlockStore;
7878
use Symfony\Component\Lock\Store\StoreFactory;
7979
use Symfony\Component\Lock\StoreInterface;
80+
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
81+
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
82+
use Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory;
83+
use Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory;
84+
use Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory;
85+
use Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory;
8086
use Symfony\Component\Mailer\Mailer;
8187
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
8288
use Symfony\Component\Messenger\MessageBus;
@@ -1955,8 +1961,24 @@ private function registerMailerConfiguration(array $config, ContainerBuilder $co
19551961
}
19561962

19571963
$loader->load('mailer.xml');
1964+
$loader->load('mailer_transports.xml');
19581965
$container->getDefinition('mailer.default_transport')->setArgument(0, $config['dsn']);
19591966

1967+
$classToServices = [
1968+
SesTransportFactory::class => 'mailer.transport_factory.amazon',
1969+
GmailTransportFactory::class => 'mailer.transport_factory.gmail',
1970+
MandrillTransportFactory::class => 'mailer.transport_factory.mailchimp',
1971+
MailgunTransportFactory::class => 'mailer.transport_factory.mailgun',
1972+
PostmarkTransportFactory::class => 'mailer.transport_factory.postmark',
1973+
SendgridTransportFactory::class => 'mailer.transport_factory.sendgrid',
1974+
];
1975+
1976+
foreach ($classToServices as $class => $service) {
1977+
if (!class_exists($class)) {
1978+
$container->removeDefinition($service);
1979+
}
1980+
}
1981+
19601982
$recipients = $config['envelope']['recipients'] ?? null;
19611983
$sender = $config['envelope']['sender'] ?? null;
19621984

src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
<service id="mailer" alias="mailer.mailer" />
1313
<service id="Symfony\Component\Mailer\MailerInterface" alias="mailer.mailer" />
1414

15+
<service id="mailer.transport_factory" class="Symfony\Component\Mailer\Transport">
16+
<argument type="tagged_iterator" tag="mailer.transport_factory" />
17+
</service>
18+
1519
<service id="mailer.default_transport" class="Symfony\Component\Mailer\Transport\TransportInterface">
16-
<factory class="Symfony\Component\Mailer\Transport" method="fromDsn" />
20+
<factory service="mailer.transport_factory" method="fromString" />
1721
<argument /> <!-- env(MAILER_DSN) -->
18-
<argument type="service" id="event_dispatcher" />
19-
<argument type="service" id="http_client" on-invalid="ignore" />
20-
<argument type="service" id="logger" on-invalid="ignore" />
2122
</service>
2223
<service id="Symfony\Component\Mailer\Transport\TransportInterface" alias="mailer.default_transport" />
2324

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<service id="mailer.transport_factory.abstract" class="Symfony\Component\Mailer\Transport\AbstractTransportFactory" abstract="true">
9+
<argument type="service" id="event_dispatcher" />
10+
<argument type="service" id="http_client" on-invalid="ignore" />
11+
<argument type="service" id="logger" on-invalid="ignore" />
12+
</service>
13+
14+
<service id="mailer.transport_factory.amazon" class="Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory" parent="mailer.transport_factory.abstract">
15+
<tag name="mailer.transport_factory" />
16+
</service>
17+
18+
<service id="mailer.transport_factory.gmail" class="Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory" parent="mailer.transport_factory.abstract">
19+
<tag name="mailer.transport_factory" />
20+
</service>
21+
22+
<service id="mailer.transport_factory.mailchimp" class="Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory" parent="mailer.transport_factory.abstract">
23+
<tag name="mailer.transport_factory" />
24+
</service>
25+
26+
<service id="mailer.transport_factory.mailgun" class="Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory" parent="mailer.transport_factory.abstract">
27+
<tag name="mailer.transport_factory" />
28+
</service>
29+
30+
<service id="mailer.transport_factory.postmark" class="Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory" parent="mailer.transport_factory.abstract">
31+
<tag name="mailer.transport_factory" />
32+
</service>
33+
34+
<service id="mailer.transport_factory.sendgrid" class="Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory" parent="mailer.transport_factory.abstract">
35+
<tag name="mailer.transport_factory" />
36+
</service>
37+
38+
<service id="mailer.transport_factory.null" class="Symfony\Component\Mailer\Transport\NullTransportFactory" parent="mailer.transport_factory.abstract">
39+
<tag name="mailer.transport_factory" />
40+
</service>
41+
42+
<service id="mailer.transport_factory.sendmail" class="Symfony\Component\Mailer\Transport\SendmailTransportFactory" parent="mailer.transport_factory.abstract">
43+
<tag name="mailer.transport_factory" />
44+
</service>
45+
46+
<service id="mailer.transport_factory.smtp" class="Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory" parent="mailer.transport_factory.abstract">
47+
<tag name="mailer.transport_factory" priority="-100" />
48+
</service>
49+
</services>
50+
</container>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Bridge\Amazon\Factory;
13+
14+
use Symfony\Component\Mailer\Bridge\Amazon;
15+
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
16+
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
17+
use Symfony\Component\Mailer\Transport\Dsn;
18+
use Symfony\Component\Mailer\Transport\TransportInterface;
19+
20+
/**
21+
* @author Konstantin Myakshin <molodchick@gmail.com>
22+
*/
23+
final class SesTransportFactory extends AbstractTransportFactory
24+
{
25+
public function create(Dsn $dsn): TransportInterface
26+
{
27+
$scheme = $dsn->getScheme();
28+
$user = $this->getUser($dsn);
29+
$password = $this->getPassword($dsn);
30+
$region = $dsn->getOption('region');
31+
32+
if ('api' === $scheme) {
33+
return new Amazon\Http\Api\SesTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
34+
}
35+
36+
if ('http' === $scheme) {
37+
return new Amazon\Http\SesTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
38+
}
39+
40+
if ('smtp' === $scheme) {
41+
return new Amazon\Smtp\SesTransport($user, $password, $region, $this->dispatcher, $this->logger);
42+
}
43+
44+
throw new UnsupportedSchemeException($dsn);
45+
}
46+
47+
public function supports(Dsn $dsn): bool
48+
{
49+
return 'ses' === $dsn->getHost();
50+
}
51+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Factory;
13+
14+
use Symfony\Component\Mailer\Bridge\Amazon;
15+
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
16+
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
17+
use Symfony\Component\Mailer\Transport\Dsn;
18+
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
19+
20+
class SesTransportFactoryTest extends TransportFactoryTestCase
21+
{
22+
public function getFactory(): TransportFactoryInterface
23+
{
24+
return new SesTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
25+
}
26+
27+
public function supportsProvider(): iterable
28+
{
29+
yield [
30+
new Dsn('api', 'ses'),
31+
true,
32+
];
33+
34+
yield [
35+
new Dsn('http', 'ses'),
36+
true,
37+
];
38+
39+
yield [
40+
new Dsn('smtp', 'ses'),
41+
true,
42+
];
43+
44+
yield [
45+
new Dsn('smtp', 'example.com'),
46+
false,
47+
];
48+
}
49+
50+
public function createProvider(): iterable
51+
{
52+
$client = $this->getClient();
53+
$dispatcher = $this->getDispatcher();
54+
$logger = $this->getLogger();
55+
56+
yield [
57+
new Dsn('api', 'ses', self::USER, self::PASSWORD),
58+
new Amazon\Http\Api\SesTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
59+
];
60+
61+
yield [
62+
new Dsn('api', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
63+
new Amazon\Http\Api\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
64+
];
65+
66+
yield [
67+
new Dsn('http', 'ses', self::USER, self::PASSWORD),
68+
new Amazon\Http\SesTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
69+
];
70+
71+
yield [
72+
new Dsn('http', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
73+
new Amazon\Http\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
74+
];
75+
76+
yield [
77+
new Dsn('smtp', 'ses', self::USER, self::PASSWORD),
78+
new Amazon\Smtp\SesTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger),
79+
];
80+
81+
yield [
82+
new Dsn('smtp', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
83+
new Amazon\Smtp\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger),
84+
];
85+
}
86+
87+
public function unsupportedSchemeProvider(): iterable
88+
{
89+
yield [new Dsn('foo', 'ses', self::USER, self::PASSWORD)];
90+
}
91+
92+
public function incompleteDsnProvider(): iterable
93+
{
94+
yield [new Dsn('smtp', 'ses', self::USER)];
95+
96+
yield [new Dsn('smtp', 'ses', null, self::PASSWORD)];
97+
}
98+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Bridge\Google\Factory;
13+
14+
use Symfony\Component\Mailer\Bridge\Google\Smtp\GmailTransport;
15+
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
16+
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
17+
use Symfony\Component\Mailer\Transport\Dsn;
18+
use Symfony\Component\Mailer\Transport\TransportInterface;
19+
20+
/**
21+
* @author Konstantin Myakshin <molodchick@gmail.com>
22+
*/
23+
final class GmailTransportFactory extends AbstractTransportFactory
24+
{
25+
public function create(Dsn $dsn): TransportInterface
26+
{
27+
if ('smtp' === $dsn->getScheme()) {
28+
return new GmailTransport($this->getUser($dsn), $this->getPassword($dsn), $this->dispatcher, $this->logger);
29+
}
30+
31+
throw new UnsupportedSchemeException($dsn);
32+
}
33+
34+
public function supports(Dsn $dsn): bool
35+
{
36+
return 'gmail' === $dsn->getHost();
37+
}
38+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Symfony\Component\Mailer\Bridge\Google\Tests\Factory;
4+
5+
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
6+
use Symfony\Component\Mailer\Bridge\Google\Smtp\GmailTransport;
7+
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
8+
use Symfony\Component\Mailer\Transport\Dsn;
9+
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
10+
11+
class GmailTransportFactoryTest extends TransportFactoryTestCase
12+
{
13+
public function getFactory(): TransportFactoryInterface
14+
{
15+
return new GmailTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
16+
}
17+
18+
public function supportsProvider(): iterable
19+
{
20+
yield [
21+
new Dsn('smtp', 'gmail'),
22+
true,
23+
];
24+
25+
yield [
26+
new Dsn('smtp', 'example.com'),
27+
false,
28+
];
29+
}
30+
31+
public function createProvider(): iterable
32+
{
33+
yield [
34+
new Dsn('smtp', 'gmail', self::USER, self::PASSWORD),
35+
new GmailTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()),
36+
];
37+
}
38+
39+
public function unsupportedSchemeProvider(): iterable
40+
{
41+
yield [new Dsn('http', 'gmail', self::USER, self::PASSWORD)];
42+
}
43+
44+
public function incompleteDsnProvider(): iterable
45+
{
46+
yield [new Dsn('smtp', 'gmail', self::USER)];
47+
48+
yield [new Dsn('smtp', 'gmail', null, self::PASSWORD)];
49+
}
50+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Bridge\Mailchimp\Factory;
13+
14+
use Symfony\Component\Mailer\Bridge\Mailchimp;
15+
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
16+
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
17+
use Symfony\Component\Mailer\Transport\Dsn;
18+
use Symfony\Component\Mailer\Transport\TransportInterface;
19+
20+
/**
21+
* @author Konstantin Myakshin <molodchick@gmail.com>
22+
*/
23+
final class MandrillTransportFactory extends AbstractTransportFactory
24+
{
25+
public function create(Dsn $dsn): TransportInterface
26+
{
27+
$scheme = $dsn->getScheme();
28+
$user = $this->getUser($dsn);
29+
30+
if ('api' === $scheme) {
31+
return new Mailchimp\Http\Api\MandrillTransport($user, $this->client, $this->dispatcher, $this->logger);
32+
}
33+
34+
if ('http' === $scheme) {
35+
return new Mailchimp\Http\MandrillTransport($user, $this->client, $this->dispatcher, $this->logger);
36+
}
37+
38+
if ('smtp' === $scheme) {
39+
$password = $this->getPassword($dsn);
40+
41+
return new Mailchimp\Smtp\MandrillTransport($user, $password, $this->dispatcher, $this->logger);
42+
}
43+
44+
throw new UnsupportedSchemeException($dsn);
45+
}
46+
47+
public function supports(Dsn $dsn): bool
48+
{
49+
return 'mandrill' === $dsn->getHost();
50+
}
51+
}

0 commit comments

Comments
 (0)