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

allow using env variables in transport configuration #159

Merged
merged 1 commit into from
Feb 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 43 additions & 59 deletions DependencyInjection/SwiftmailerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
Expand Down Expand Up @@ -66,68 +67,60 @@ public function load(array $configs, ContainerBuilder $container)

protected function configureMailer($name, array $mailer, ContainerBuilder $container, $isDefaultMailer = false)
{
if (null === $mailer['transport']) {
$transport = 'null';
} elseif ('gmail' === $mailer['transport']) {
$mailer['encryption'] = 'ssl';
$mailer['auth_mode'] = 'login';
$mailer['host'] = 'smtp.gmail.com';
$transport = 'smtp';
} else {
$transport = $mailer['transport'];
}

if (null !== $mailer['url']) {
$parts = parse_url($mailer['url']);
if (!empty($parts['scheme'])) {
$transport = $parts['scheme'];
}
$definitionDecorator = $this->createChildDefinition('swiftmailer.transport.eventdispatcher.abstract');
$container
->setDefinition(sprintf('swiftmailer.mailer.%s.transport.eventdispatcher', $name), $definitionDecorator)
;

if (!empty($parts['user'])) {
$mailer['username'] = $parts['user'];
}
if (!empty($parts['pass'])) {
$mailer['password'] = $parts['pass'];
}
if (!empty($parts['host'])) {
$mailer['host'] = $parts['host'];
}
if (!empty($parts['port'])) {
$mailer['port'] = $parts['port'];
}
if (!empty($parts['query'])) {
$query = array();
parse_str($parts['query'], $query);
if (!empty($query['encryption'])) {
$mailer['encryption'] = $query['encryption'];
}
if (!empty($query['auth_mode'])) {
$mailer['auth_mode'] = $query['auth_mode'];
}
if (method_exists($container, 'resolveEnvPlaceholders')) {
$options = array();
$envVariablesAllowed = array('transport', 'url', 'username', 'password', 'host', 'port', 'timeout', 'source_ip', 'local_domain', 'encryption', 'auth_mode');
foreach ($envVariablesAllowed as $key) {
$container->resolveEnvPlaceholders($mailer[$key], null, $usedEnvs);
$options[$key] = $mailer[$key];
}
} else {
$usedEnvs = false;
}
unset($mailer['url']);

$container->setParameter(sprintf('swiftmailer.mailer.%s.transport.name', $name), $transport);
if ($usedEnvs) {
$transportId = sprintf('swiftmailer.mailer.%s.transport.dynamic', $name);
$definitionDecorator = new Definition('\Swift_Transport');
$definitionDecorator->setFactory(array('Symfony\Bundle\SwiftmailerBundle\DependencyInjection\SwiftmailerTransportFactory', 'createTransport'));
$definitionDecorator->setArguments(array(
$options,
new Reference('router.request_context'),
new Reference(sprintf('swiftmailer.mailer.%s.transport.eventdispatcher', $name)),
));
$container->setDefinition(sprintf('swiftmailer.mailer.%s.transport.dynamic', $name), $definitionDecorator);
$container->setAlias(sprintf('swiftmailer.mailer.%s.transport', $name), $transportId);

$definitionDecorator = $this->createChildDefinition('swiftmailer.mailer.abstract');
$container
->setDefinition(sprintf('swiftmailer.mailer.%s', $name), $definitionDecorator)
->replaceArgument(0, new Reference(sprintf('swiftmailer.mailer.%s.transport', $name)))
;

if (isset($mailer['disable_delivery']) && $mailer['disable_delivery']) {
$transport = 'null';
$container->setParameter(sprintf('swiftmailer.mailer.%s.delivery.enabled', $name), false);
$container->setParameter(sprintf('swiftmailer.mailer.%s.transport.name', $name), 'dynamic');
} else {
$container->setParameter(sprintf('swiftmailer.mailer.%s.delivery.enabled', $name), true);
}
$mailer = SwiftmailerTransportFactory::resolveOptions($mailer);
$transport = $mailer['transport'];

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

$this->configureMailerTransport($name, $mailer, $container, $transport, $isDefaultMailer);
$this->configureMailerSpool($name, $mailer, $container, $transport, $isDefaultMailer);
$transportId = in_array($transport, array('smtp', 'sendmail', 'null'))
? sprintf('swiftmailer.mailer.%s.transport.%s', $name, $transport)
: $transport;

$this->configureMailerTransport($name, $mailer, $container, $transport, $isDefaultMailer);
}
$this->configureMailerSpool($name, $mailer, $container, $transportId, $isDefaultMailer);
$this->configureMailerSenderAddress($name, $mailer, $container, $isDefaultMailer);
$this->configureMailerAntiFlood($name, $mailer, $container, $isDefaultMailer);
$this->configureMailerDeliveryAddress($name, $mailer, $container, $isDefaultMailer);
$this->configureMailerLogging($name, $mailer, $container, $isDefaultMailer);

$container->setParameter(sprintf('swiftmailer.mailer.%s.delivery.enabled', $name), empty($mailer['disable_delivery']));

// alias
if ($isDefaultMailer) {
$container->setAlias('swiftmailer.mailer', sprintf('swiftmailer.mailer.%s', $name));
Expand All @@ -144,11 +137,6 @@ protected function configureMailerTransport($name, array $mailer, ContainerBuild
$container->setParameter(sprintf('swiftmailer.mailer.%s.transport.smtp.%s', $name, $key), $mailer[$key]);
}

$definitionDecorator = $this->createChildDefinition('swiftmailer.transport.eventdispatcher.abstract');
$container
->setDefinition(sprintf('swiftmailer.mailer.%s.transport.eventdispatcher', $name), $definitionDecorator)
;

if ('smtp' === $transport) {
$authDecorator = $this->createChildDefinition('swiftmailer.transport.authhandler.abstract');
$container
Expand Down Expand Up @@ -278,10 +266,6 @@ protected function configureMailerSpool($name, array $mailer, ContainerBuilder $
))
;

if (in_array($transport, array('smtp', 'mail', 'sendmail', 'null'))) {
// built-in transport
$transport = sprintf('swiftmailer.mailer.%s.transport.%s', $name, $transport);
}
$container->setAlias(sprintf('swiftmailer.mailer.%s.transport.real', $name), $transport);
$container->setAlias(sprintf('swiftmailer.mailer.%s.transport', $name), sprintf('swiftmailer.mailer.%s.transport.spool', $name));
$container->setParameter(sprintf('swiftmailer.mailer.%s.spool.enabled', $name), true);
Expand Down
138 changes: 138 additions & 0 deletions DependencyInjection/SwiftmailerTransportFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\SwiftmailerBundle\DependencyInjection;

use Symfony\Component\Routing\RequestContext;

/**
* Factory to create a \Swift_Transport object.
*
* @author Romain Gautier <[email protected]>
*/
class SwiftmailerTransportFactory
{
/**
* @param array $options
* @param RequestContext $requestContext
* @param \Swift_Events_EventDispatcher $eventDispatcher
*
* @return \Swift_Transport
*
* @throws \InvalidArgumentException if the scheme is not a built-in Swiftmailer transport
*/
public static function createTransport(array $options, RequestContext $requestContext, \Swift_Events_EventDispatcher $eventDispatcher)
{
$options = static::resolveOptions($options);

if ('smtp' === $options['transport']) {
$smtpAuthHandler = new \Swift_Transport_Esmtp_AuthHandler(array(
new \Swift_Transport_Esmtp_Auth_CramMd5Authenticator(),
new \Swift_Transport_Esmtp_Auth_LoginAuthenticator(),
new \Swift_Transport_Esmtp_Auth_PlainAuthenticator(),
));
$smtpAuthHandler->setUsername($options['username']);
$smtpAuthHandler->setPassword($options['password']);
$smtpAuthHandler->setAuthMode($options['auth_mode']);

$transport = new \Swift_Transport_EsmtpTransport(
new \Swift_Transport_StreamBuffer(new \Swift_StreamFilters_StringReplacementFilterFactory()),
array($smtpAuthHandler),
$eventDispatcher
);
$transport->setHost($options['host']);
$transport->setPort($options['port']);
$transport->setEncryption($options['encryption']);
$transport->setTimeout($options['timeout']);
$transport->setSourceIp($options['source_ip']);

$smtpTransportConfigurator = new SmtpTransportConfigurator(null, $requestContext);
$smtpTransportConfigurator->configure($transport);
} elseif ('sendmail' === $options['transport']) {
$transport = new \Swift_Transport_SendmailTransport(
new \Swift_Transport_StreamBuffer(new \Swift_StreamFilters_StringReplacementFilterFactory()),
$eventDispatcher
);

$smtpTransportConfigurator = new SmtpTransportConfigurator(null, $requestContext);
$smtpTransportConfigurator->configure($transport);
} elseif ('null' === $options['transport']) {
$transport = new \Swift_Transport_NullTransport($eventDispatcher);
} else {
throw new \InvalidArgumentException(sprintf('Not a built-in Swiftmailer transport: %s.', $options['transport']));
}

return $transport;
}

/**
* @param array $options
*
* @return array options
*/
public static function resolveOptions(array $options)
{
$options += array(
'transport' => null,
'username' => null,
'password' => null,
'host' => null,
'port' => null,
'timeout' => null,
'source_ip' => null,
'local_domain' => null,
'encryption' => null,
'auth_mode' => null,
);

if (isset($options['url'])) {
$parts = parse_url($options['url']);
if (isset($parts['scheme'])) {
$options['transport'] = $parts['scheme'];
}
if (isset($parts['user'])) {
$options['username'] = $parts['user'];
}
if (isset($parts['pass'])) {
$options['password'] = $parts['pass'];
}
if (isset($parts['host'])) {
$options['host'] = $parts['host'];
}
if (isset($parts['port'])) {
$options['port'] = $parts['port'];
}
if (isset($parts['query'])) {
parse_str($parts['query'], $query);
foreach ($options as $key => $value) {
if (isset($query[$key])) {
$options[$key] = $query[$key];
}
}
}
}

if (!isset($options['transport'])) {
$options['transport'] = 'null';
} elseif ('gmail' === $options['transport']) {
$options['encryption'] = 'ssl';
$options['auth_mode'] = 'login';
$options['host'] = 'smtp.gmail.com';
$options['transport'] = 'smtp';
}

if (!isset($options['port'])) {
$options['port'] = 'ssl' === $options['encryption'] ? 465 : 25;
}

return $options;
}
}
2 changes: 1 addition & 1 deletion Tests/DependencyInjection/Fixtures/config/php/urls.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'default_mailer' => 'smtp_mailer',
'mailers' => array(
'smtp_mailer' => array(
'url' => 'smtp://username:[email protected]:12345?encryption=tls&auth_mode=login',
'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',
),
),
));
2 changes: 1 addition & 1 deletion Tests/DependencyInjection/Fixtures/config/xml/urls.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<swiftmailer:config default-mailer="smtp_mailer">
<swiftmailer:mailer name="smtp_mailer"
url="smtp://username:[email protected]:12345?encryption=tls&amp;auth_mode=login">
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">
</swiftmailer:mailer>
</swiftmailer:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
swiftmailer:
url: '%env(SWIFTMAILER_URL)%'
2 changes: 1 addition & 1 deletion Tests/DependencyInjection/Fixtures/config/yml/urls.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ swiftmailer:
default_mailer: smtp_mailer
mailers:
smtp_mailer:
url: smtp://username:[email protected]:12345?encryption=tls&auth_mode=login
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
46 changes: 39 additions & 7 deletions Tests/DependencyInjection/SwiftmailerExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,47 @@
namespace Symfony\Bundle\SwiftmailerBundle\Tests\DependencyInjection;

use Symfony\Bundle\SwiftmailerBundle\DependencyInjection\SwiftmailerExtension;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\RequestContext;

class SwiftmailerExtensionTest extends \PHPUnit_Framework_TestCase
{
public function testLoadWithEnvVariables()
{
$container = new ContainerBuilder();
if (!method_exists($container, 'resolveEnvPlaceholders')) {
$this->markTestSkipped('Runtime environment variables has been introduced in the Dependency Injection version 3.2.');
}

$container->setParameter('kernel.debug', false);
$container->setParameter('kernel.cache_dir', '/tmp');

$container->set('swiftmailer.mailer.default.transport.eventdispatcher', new \Swift_Events_SimpleEventDispatcher());
$container->set('router.request_context', new RequestContext());

$container->registerExtension(new SwiftmailerExtension());
$locator = new FileLocator(__DIR__.'/Fixtures/config/yml');
$loader = new YamlFileLoader($container, $locator);
$loader->load('env_variable.yml');

$container->getCompilerPassConfig()->setOptimizationPasses(array(
new ResolveDefinitionTemplatesPass(),
));
$container->getCompilerPassConfig()->setRemovingPasses(array());
$container->compile();

$this->assertEquals(
array('Symfony\Bundle\SwiftmailerBundle\DependencyInjection\SwiftmailerTransportFactory', 'createTransport'),
$container->findDefinition('swiftmailer.transport')->getFactory()
);
$this->assertSame('dynamic', $container->getParameter('swiftmailer.mailer.default.transport.name'));
}

public function getConfigTypes()
{
return array(
Expand Down Expand Up @@ -175,11 +207,11 @@ public function testUrls($type)
{
$container = $this->loadContainerFromFile('urls', $type);

$this->assertEquals('example.com', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.host'));
$this->assertEquals('12345', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.port'));
$this->assertEquals('example.org', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.host'));
$this->assertEquals('23456', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.port'));
$this->assertEquals('tls', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.encryption'));
$this->assertEquals('username', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.username'));
$this->assertEquals('password', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.password'));
$this->assertEquals('user', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.username'));
$this->assertEquals('pass', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.password'));
$this->assertEquals('login', $container->getParameter('swiftmailer.mailer.smtp_mailer.transport.smtp.auth_mode'));
}

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

$container->getCompilerPassConfig()->setOptimizationPasses(array(
new ResolveDefinitionTemplatesPass()
new ResolveDefinitionTemplatesPass(),
));
$container->getCompilerPassConfig()->setRemovingPasses(array());
$container->compile();
Expand Down
Loading