Skip to content
This repository was archived by the owner on Feb 6, 2022. It is now read-only.

Commit 2027dae

Browse files
committed
feature #159 allow using env variables in transport configuration (mykiwi)
This PR was merged into the 2.5-dev branch. Discussion ---------- allow using env variables in transport configuration Example: ```yml # MAILER_URL=transport://user:pass@host:port/?encryption=...&auth_mode=... swiftmailer: url: "%env(MAILER_URL)%" ``` To do: - [x] add the doc symfony/symfony-docs/pull/7510 - [x] add tests Commits ------- 183b291 allow using env variables in transport configuration
2 parents bf268a4 + 183b291 commit 2027dae

File tree

8 files changed

+491
-69
lines changed

8 files changed

+491
-69
lines changed

DependencyInjection/SwiftmailerExtension.php

Lines changed: 43 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
1515
use Symfony\Component\DependencyInjection\ContainerInterface;
1616
use Symfony\Component\DependencyInjection\ChildDefinition;
17+
use Symfony\Component\DependencyInjection\Definition;
1718
use Symfony\Component\DependencyInjection\DefinitionDecorator;
1819
use Symfony\Component\DependencyInjection\Reference;
1920
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
@@ -66,68 +67,60 @@ public function load(array $configs, ContainerBuilder $container)
6667

6768
protected function configureMailer($name, array $mailer, ContainerBuilder $container, $isDefaultMailer = false)
6869
{
69-
if (null === $mailer['transport']) {
70-
$transport = 'null';
71-
} elseif ('gmail' === $mailer['transport']) {
72-
$mailer['encryption'] = 'ssl';
73-
$mailer['auth_mode'] = 'login';
74-
$mailer['host'] = 'smtp.gmail.com';
75-
$transport = 'smtp';
76-
} else {
77-
$transport = $mailer['transport'];
78-
}
79-
80-
if (null !== $mailer['url']) {
81-
$parts = parse_url($mailer['url']);
82-
if (!empty($parts['scheme'])) {
83-
$transport = $parts['scheme'];
84-
}
70+
$definitionDecorator = $this->createChildDefinition('swiftmailer.transport.eventdispatcher.abstract');
71+
$container
72+
->setDefinition(sprintf('swiftmailer.mailer.%s.transport.eventdispatcher', $name), $definitionDecorator)
73+
;
8574

86-
if (!empty($parts['user'])) {
87-
$mailer['username'] = $parts['user'];
88-
}
89-
if (!empty($parts['pass'])) {
90-
$mailer['password'] = $parts['pass'];
91-
}
92-
if (!empty($parts['host'])) {
93-
$mailer['host'] = $parts['host'];
94-
}
95-
if (!empty($parts['port'])) {
96-
$mailer['port'] = $parts['port'];
97-
}
98-
if (!empty($parts['query'])) {
99-
$query = array();
100-
parse_str($parts['query'], $query);
101-
if (!empty($query['encryption'])) {
102-
$mailer['encryption'] = $query['encryption'];
103-
}
104-
if (!empty($query['auth_mode'])) {
105-
$mailer['auth_mode'] = $query['auth_mode'];
106-
}
75+
if (method_exists($container, 'resolveEnvPlaceholders')) {
76+
$options = array();
77+
$envVariablesAllowed = array('transport', 'url', 'username', 'password', 'host', 'port', 'timeout', 'source_ip', 'local_domain', 'encryption', 'auth_mode');
78+
foreach ($envVariablesAllowed as $key) {
79+
$container->resolveEnvPlaceholders($mailer[$key], null, $usedEnvs);
80+
$options[$key] = $mailer[$key];
10781
}
82+
} else {
83+
$usedEnvs = false;
10884
}
109-
unset($mailer['url']);
110-
111-
$container->setParameter(sprintf('swiftmailer.mailer.%s.transport.name', $name), $transport);
85+
if ($usedEnvs) {
86+
$transportId = sprintf('swiftmailer.mailer.%s.transport.dynamic', $name);
87+
$definitionDecorator = new Definition('\Swift_Transport');
88+
$definitionDecorator->setFactory(array('Symfony\Bundle\SwiftmailerBundle\DependencyInjection\SwiftmailerTransportFactory', 'createTransport'));
89+
$definitionDecorator->setArguments(array(
90+
$options,
91+
new Reference('router.request_context'),
92+
new Reference(sprintf('swiftmailer.mailer.%s.transport.eventdispatcher', $name)),
93+
));
94+
$container->setDefinition(sprintf('swiftmailer.mailer.%s.transport.dynamic', $name), $definitionDecorator);
95+
$container->setAlias(sprintf('swiftmailer.mailer.%s.transport', $name), $transportId);
96+
97+
$definitionDecorator = $this->createChildDefinition('swiftmailer.mailer.abstract');
98+
$container
99+
->setDefinition(sprintf('swiftmailer.mailer.%s', $name), $definitionDecorator)
100+
->replaceArgument(0, new Reference(sprintf('swiftmailer.mailer.%s.transport', $name)))
101+
;
112102

113-
if (isset($mailer['disable_delivery']) && $mailer['disable_delivery']) {
114-
$transport = 'null';
115-
$container->setParameter(sprintf('swiftmailer.mailer.%s.delivery.enabled', $name), false);
103+
$container->setParameter(sprintf('swiftmailer.mailer.%s.transport.name', $name), 'dynamic');
116104
} else {
117-
$container->setParameter(sprintf('swiftmailer.mailer.%s.delivery.enabled', $name), true);
118-
}
105+
$mailer = SwiftmailerTransportFactory::resolveOptions($mailer);
106+
$transport = $mailer['transport'];
119107

120-
if (empty($mailer['port'])) {
121-
$mailer['port'] = 'ssl' === $mailer['encryption'] ? 465 : 25;
122-
}
108+
$container->setParameter(sprintf('swiftmailer.mailer.%s.transport.name', $name), $transport);
123109

124-
$this->configureMailerTransport($name, $mailer, $container, $transport, $isDefaultMailer);
125-
$this->configureMailerSpool($name, $mailer, $container, $transport, $isDefaultMailer);
110+
$transportId = in_array($transport, array('smtp', 'sendmail', 'null'))
111+
? sprintf('swiftmailer.mailer.%s.transport.%s', $name, $transport)
112+
: $transport;
113+
114+
$this->configureMailerTransport($name, $mailer, $container, $transport, $isDefaultMailer);
115+
}
116+
$this->configureMailerSpool($name, $mailer, $container, $transportId, $isDefaultMailer);
126117
$this->configureMailerSenderAddress($name, $mailer, $container, $isDefaultMailer);
127118
$this->configureMailerAntiFlood($name, $mailer, $container, $isDefaultMailer);
128119
$this->configureMailerDeliveryAddress($name, $mailer, $container, $isDefaultMailer);
129120
$this->configureMailerLogging($name, $mailer, $container, $isDefaultMailer);
130121

122+
$container->setParameter(sprintf('swiftmailer.mailer.%s.delivery.enabled', $name), empty($mailer['disable_delivery']));
123+
131124
// alias
132125
if ($isDefaultMailer) {
133126
$container->setAlias('swiftmailer.mailer', sprintf('swiftmailer.mailer.%s', $name));
@@ -144,11 +137,6 @@ protected function configureMailerTransport($name, array $mailer, ContainerBuild
144137
$container->setParameter(sprintf('swiftmailer.mailer.%s.transport.smtp.%s', $name, $key), $mailer[$key]);
145138
}
146139

147-
$definitionDecorator = $this->createChildDefinition('swiftmailer.transport.eventdispatcher.abstract');
148-
$container
149-
->setDefinition(sprintf('swiftmailer.mailer.%s.transport.eventdispatcher', $name), $definitionDecorator)
150-
;
151-
152140
if ('smtp' === $transport) {
153141
$authDecorator = $this->createChildDefinition('swiftmailer.transport.authhandler.abstract');
154142
$container
@@ -278,10 +266,6 @@ protected function configureMailerSpool($name, array $mailer, ContainerBuilder $
278266
))
279267
;
280268

281-
if (in_array($transport, array('smtp', 'mail', 'sendmail', 'null'))) {
282-
// built-in transport
283-
$transport = sprintf('swiftmailer.mailer.%s.transport.%s', $name, $transport);
284-
}
285269
$container->setAlias(sprintf('swiftmailer.mailer.%s.transport.real', $name), $transport);
286270
$container->setAlias(sprintf('swiftmailer.mailer.%s.transport', $name), sprintf('swiftmailer.mailer.%s.transport.spool', $name));
287271
$container->setParameter(sprintf('swiftmailer.mailer.%s.spool.enabled', $name), true);
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Bundle\SwiftmailerBundle\DependencyInjection;
13+
14+
use Symfony\Component\Routing\RequestContext;
15+
16+
/**
17+
* Factory to create a \Swift_Transport object.
18+
*
19+
* @author Romain Gautier <[email protected]>
20+
*/
21+
class SwiftmailerTransportFactory
22+
{
23+
/**
24+
* @param array $options
25+
* @param RequestContext $requestContext
26+
* @param \Swift_Events_EventDispatcher $eventDispatcher
27+
*
28+
* @return \Swift_Transport
29+
*
30+
* @throws \InvalidArgumentException if the scheme is not a built-in Swiftmailer transport
31+
*/
32+
public static function createTransport(array $options, RequestContext $requestContext, \Swift_Events_EventDispatcher $eventDispatcher)
33+
{
34+
$options = static::resolveOptions($options);
35+
36+
if ('smtp' === $options['transport']) {
37+
$smtpAuthHandler = new \Swift_Transport_Esmtp_AuthHandler(array(
38+
new \Swift_Transport_Esmtp_Auth_CramMd5Authenticator(),
39+
new \Swift_Transport_Esmtp_Auth_LoginAuthenticator(),
40+
new \Swift_Transport_Esmtp_Auth_PlainAuthenticator(),
41+
));
42+
$smtpAuthHandler->setUsername($options['username']);
43+
$smtpAuthHandler->setPassword($options['password']);
44+
$smtpAuthHandler->setAuthMode($options['auth_mode']);
45+
46+
$transport = new \Swift_Transport_EsmtpTransport(
47+
new \Swift_Transport_StreamBuffer(new \Swift_StreamFilters_StringReplacementFilterFactory()),
48+
array($smtpAuthHandler),
49+
$eventDispatcher
50+
);
51+
$transport->setHost($options['host']);
52+
$transport->setPort($options['port']);
53+
$transport->setEncryption($options['encryption']);
54+
$transport->setTimeout($options['timeout']);
55+
$transport->setSourceIp($options['source_ip']);
56+
57+
$smtpTransportConfigurator = new SmtpTransportConfigurator(null, $requestContext);
58+
$smtpTransportConfigurator->configure($transport);
59+
} elseif ('sendmail' === $options['transport']) {
60+
$transport = new \Swift_Transport_SendmailTransport(
61+
new \Swift_Transport_StreamBuffer(new \Swift_StreamFilters_StringReplacementFilterFactory()),
62+
$eventDispatcher
63+
);
64+
65+
$smtpTransportConfigurator = new SmtpTransportConfigurator(null, $requestContext);
66+
$smtpTransportConfigurator->configure($transport);
67+
} elseif ('null' === $options['transport']) {
68+
$transport = new \Swift_Transport_NullTransport($eventDispatcher);
69+
} else {
70+
throw new \InvalidArgumentException(sprintf('Not a built-in Swiftmailer transport: %s.', $options['transport']));
71+
}
72+
73+
return $transport;
74+
}
75+
76+
/**
77+
* @param array $options
78+
*
79+
* @return array options
80+
*/
81+
public static function resolveOptions(array $options)
82+
{
83+
$options += array(
84+
'transport' => null,
85+
'username' => null,
86+
'password' => null,
87+
'host' => null,
88+
'port' => null,
89+
'timeout' => null,
90+
'source_ip' => null,
91+
'local_domain' => null,
92+
'encryption' => null,
93+
'auth_mode' => null,
94+
);
95+
96+
if (isset($options['url'])) {
97+
$parts = parse_url($options['url']);
98+
if (isset($parts['scheme'])) {
99+
$options['transport'] = $parts['scheme'];
100+
}
101+
if (isset($parts['user'])) {
102+
$options['username'] = $parts['user'];
103+
}
104+
if (isset($parts['pass'])) {
105+
$options['password'] = $parts['pass'];
106+
}
107+
if (isset($parts['host'])) {
108+
$options['host'] = $parts['host'];
109+
}
110+
if (isset($parts['port'])) {
111+
$options['port'] = $parts['port'];
112+
}
113+
if (isset($parts['query'])) {
114+
parse_str($parts['query'], $query);
115+
foreach ($options as $key => $value) {
116+
if (isset($query[$key])) {
117+
$options[$key] = $query[$key];
118+
}
119+
}
120+
}
121+
}
122+
123+
if (!isset($options['transport'])) {
124+
$options['transport'] = 'null';
125+
} elseif ('gmail' === $options['transport']) {
126+
$options['encryption'] = 'ssl';
127+
$options['auth_mode'] = 'login';
128+
$options['host'] = 'smtp.gmail.com';
129+
$options['transport'] = 'smtp';
130+
}
131+
132+
if (!isset($options['port'])) {
133+
$options['port'] = 'ssl' === $options['encryption'] ? 465 : 25;
134+
}
135+
136+
return $options;
137+
}
138+
}

Tests/DependencyInjection/Fixtures/config/php/urls.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
'default_mailer' => 'smtp_mailer',
55
'mailers' => array(
66
'smtp_mailer' => array(
7-
'url' => 'smtp://username:[email protected]:12345?encryption=tls&auth_mode=login',
7+
'url' => 'smtp://username:[email protected]:12345?transport=smtp&username=user&password=pass&host=example.org&port=23456&timeout=42&source_ip=127.0.0.1&local_domain=local.example.com&encryption=tls&auth_mode=login',
88
),
99
),
1010
));

Tests/DependencyInjection/Fixtures/config/xml/urls.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
<swiftmailer:config default-mailer="smtp_mailer">
99
<swiftmailer:mailer name="smtp_mailer"
10-
url="smtp://username:[email protected]:12345?encryption=tls&amp;auth_mode=login">
10+
url="smtp://username:[email protected]:12345?transport=smtp&amp;username=user&amp;password=pass&amp;host=example.org&amp;port=23456&amp;timeout=42&amp;source_ip=127.0.0.1&amp;local_domain=local.example.com&amp;encryption=tls&amp;auth_mode=login">
1111
</swiftmailer:mailer>
1212
</swiftmailer:config>
1313
</container>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
swiftmailer:
2+
url: '%env(SWIFTMAILER_URL)%'

Tests/DependencyInjection/Fixtures/config/yml/urls.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ swiftmailer:
22
default_mailer: smtp_mailer
33
mailers:
44
smtp_mailer:
5-
url: smtp://username:[email protected]:12345?encryption=tls&auth_mode=login
5+
url: smtp://username:[email protected]:12345?transport=smtp&username=user&password=pass&host=example.org&port=23456&timeout=42&source_ip=127.0.0.1&local_domain=local.example.com&encryption=tls&auth_mode=login

Tests/DependencyInjection/SwiftmailerExtensionTest.php

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,47 @@
1212
namespace Symfony\Bundle\SwiftmailerBundle\Tests\DependencyInjection;
1313

1414
use Symfony\Bundle\SwiftmailerBundle\DependencyInjection\SwiftmailerExtension;
15+
use Symfony\Component\Config\FileLocator;
1516
use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
18+
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
1719
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
1820
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
19-
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
20-
use Symfony\Component\Config\FileLocator;
21+
use Symfony\Component\Routing\RequestContext;
2122

2223
class SwiftmailerExtensionTest extends \PHPUnit_Framework_TestCase
2324
{
25+
public function testLoadWithEnvVariables()
26+
{
27+
$container = new ContainerBuilder();
28+
if (!method_exists($container, 'resolveEnvPlaceholders')) {
29+
$this->markTestSkipped('Runtime environment variables has been introduced in the Dependency Injection version 3.2.');
30+
}
31+
32+
$container->setParameter('kernel.debug', false);
33+
$container->setParameter('kernel.cache_dir', '/tmp');
34+
35+
$container->set('swiftmailer.mailer.default.transport.eventdispatcher', new \Swift_Events_SimpleEventDispatcher());
36+
$container->set('router.request_context', new RequestContext());
37+
38+
$container->registerExtension(new SwiftmailerExtension());
39+
$locator = new FileLocator(__DIR__.'/Fixtures/config/yml');
40+
$loader = new YamlFileLoader($container, $locator);
41+
$loader->load('env_variable.yml');
42+
43+
$container->getCompilerPassConfig()->setOptimizationPasses(array(
44+
new ResolveDefinitionTemplatesPass(),
45+
));
46+
$container->getCompilerPassConfig()->setRemovingPasses(array());
47+
$container->compile();
48+
49+
$this->assertEquals(
50+
array('Symfony\Bundle\SwiftmailerBundle\DependencyInjection\SwiftmailerTransportFactory', 'createTransport'),
51+
$container->findDefinition('swiftmailer.transport')->getFactory()
52+
);
53+
$this->assertSame('dynamic', $container->getParameter('swiftmailer.mailer.default.transport.name'));
54+
}
55+
2456
public function getConfigTypes()
2557
{
2658
return array(
@@ -175,11 +207,11 @@ public function testUrls($type)
175207
{
176208
$container = $this->loadContainerFromFile('urls', $type);
177209

178-
$this->assertEquals('example.com', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.host'));
179-
$this->assertEquals('12345', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.port'));
210+
$this->assertEquals('example.org', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.host'));
211+
$this->assertEquals('23456', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.port'));
180212
$this->assertEquals('tls', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.encryption'));
181-
$this->assertEquals('username', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.username'));
182-
$this->assertEquals('password', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.password'));
213+
$this->assertEquals('user', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.username'));
214+
$this->assertEquals('pass', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.password'));
183215
$this->assertEquals('login', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.auth_mode'));
184216
}
185217

@@ -389,7 +421,7 @@ private function loadContainerFromFile($file, $type, array $services = array())
389421
$loader->load($file.'.'.$type);
390422

391423
$container->getCompilerPassConfig()->setOptimizationPasses(array(
392-
new ResolveDefinitionTemplatesPass()
424+
new ResolveDefinitionTemplatesPass(),
393425
));
394426
$container->getCompilerPassConfig()->setRemovingPasses(array());
395427
$container->compile();

0 commit comments

Comments
 (0)