Skip to content

Commit

Permalink
Add an adapter to support the Symfony Mailer component and deprecate …
Browse files Browse the repository at this point in the history
…the Swiftmailer integration

Co-authored-by: Michael Babker <[email protected]>
  • Loading branch information
pocky and mbabker committed May 10, 2022
1 parent ac1af41 commit ad5eaf1
Show file tree
Hide file tree
Showing 17 changed files with 468 additions and 128 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@

/composer.phar
/composer.lock

/.phpunit.result.cache
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"php": "^8.0",
"sylius-labs/polyfill-symfony-event-dispatcher": "^1.0",
"symfony/config": "^5.4",
"symfony/deprecation-contracts": "^2.1 || ^3.0",
"symfony/dependency-injection": "^5.4",
"symfony/framework-bundle": "^5.4",
"symfony/http-kernel": "^5.4",
Expand All @@ -46,6 +47,8 @@
"sylius-labs/coding-standard": "^4.0",
"symfony/console": "^5.4",
"symfony/dotenv": "^5.4",
"symfony/event-dispatcher": "^5.4",
"symfony/mailer": "^5.4",
"symfony/swiftmailer-bundle": "^3.1",
"symfony/twig-bundle": "^5.4",
"vimeo/psalm": "^4.22",
Expand Down
1 change: 1 addition & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ parameters:

- '/Parameter \#1 \$event of method Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface::dispatch\(\) expects object, string given\./'
- '/Method Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface::dispatch\(\) invoked with 2 parameters, 1 required\./'
- '/Cannot call method has\(\) on object\|null/'
- '/Property Sylius\\Component\\Mailer\\Model\\Email\:\:\$id is never written\, only read\./'
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\MailerBundle\DependencyInjection\Compiler;

use Sylius\Bundle\MailerBundle\Renderer\Adapter\EmailTwigAdapter;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;

final class RegisterRendererAdapterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if ($container->hasAlias('sylius.email_renderer.adapter')) {
return;
}

if ($container->has('twig')) {
$twigAdapter = new ChildDefinition('sylius.email_renderer.adapter.abstract');
$twigAdapter->setClass(EmailTwigAdapter::class);
$twigAdapter->setArguments([new Reference('twig'), new Reference('event_dispatcher', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]);
$twigAdapter->setPublic(true);

$container->setDefinition('sylius.email_renderer.adapter.twig', $twigAdapter);
$container->setAlias('sylius.email_renderer.adapter', 'sylius.email_renderer.adapter.twig');

return;
}

$container->setAlias('sylius.email_renderer.adapter', 'sylius.email_renderer.adapter.default');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\MailerBundle\DependencyInjection\Compiler;

use Sylius\Bundle\MailerBundle\Sender\Adapter\SwiftMailerAdapter;
use Sylius\Bundle\MailerBundle\Sender\Adapter\SymfonyMailerAdapter;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;

final class RegisterSenderAdapterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if ($container->hasAlias('sylius.email_sender.adapter')) {
return;
}

if ($container->has('swiftmailer.mailer.default')) {
$swiftmailerAdapter = new ChildDefinition('sylius.email_sender.adapter.abstract');
/** @psalm-suppress DeprecatedClass */
$swiftmailerAdapter->setClass(SwiftMailerAdapter::class);
$swiftmailerAdapter->setArguments([new Reference('swiftmailer.mailer.default'), new Reference('event_dispatcher', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]);
$swiftmailerAdapter->setPublic(true);
$swiftmailerAdapter->setDeprecated(
'sylius/mailer-bundle',
'1.8',
'The "%service_id%" service is deprecated, use the Symfony Mailer integration instead.'
);

$container->setDefinition('sylius.email_sender.adapter.swiftmailer', $swiftmailerAdapter);
$container->setAlias('sylius.email_sender.adapter', 'sylius.email_sender.adapter.swiftmailer');

return;
}

if ($container->has('mailer.mailer')) {
$symfonyMailerAdapter = new ChildDefinition('sylius.email_sender.adapter.abstract');
$symfonyMailerAdapter->setClass(SymfonyMailerAdapter::class);
$symfonyMailerAdapter->setArguments([new Reference('mailer.mailer')]);
$symfonyMailerAdapter->setPublic(true);

$container->setDefinition('sylius.email_sender.adapter.symfony_mailer', $symfonyMailerAdapter);
$container->setAlias('sylius.email_sender.adapter', 'sylius.email_sender.adapter.symfony_mailer');

return;
}

$container->setAlias('sylius.email_sender.adapter', 'sylius.email_sender.adapter.default');
}
}
74 changes: 13 additions & 61 deletions src/Bundle/DependencyInjection/SyliusMailerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,18 @@

namespace Sylius\Bundle\MailerBundle\DependencyInjection;

use Sylius\Bundle\MailerBundle\Renderer\Adapter\EmailTwigAdapter;
use Sylius\Bundle\MailerBundle\Sender\Adapter\SwiftMailerAdapter;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;

final class SyliusMailerExtension extends Extension
final class SyliusMailerExtension extends ConfigurableExtension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container): void
protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void
{
$config = $this->processConfiguration($this->getConfiguration([], $container), $configs);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));

$configFiles = [
Expand All @@ -40,63 +35,20 @@ public function load(array $configs, ContainerBuilder $container): void
$loader->load($configFile);
}

$this->configureSenderAdapter($container, $config);
$this->configureRendererAdapter($container, $config);

$container->setParameter('sylius.mailer.sender_name', $config['sender']['name']);
$container->setParameter('sylius.mailer.sender_address', $config['sender']['address']);

$templates = $config['templates'] ?? ['Default' => '@SyliusMailer/default.html.twig'];

$container->setParameter('sylius.mailer.emails', $config['emails']);
$container->setParameter('sylius.mailer.templates', $templates);
}

/**
* {@inheritdoc}
*/
public function getConfiguration(array $config, ContainerBuilder $container): Configuration
{
$configuration = new Configuration();

$container->addObjectResource($configuration);

return $configuration;
}

private function configureSenderAdapter(ContainerBuilder $container, array $config): void
{
$bundles = (array) $container->getParameter('kernel.bundles');

$defaultSenderAdapter = 'sylius.email_sender.adapter.default';
if (array_key_exists('SwiftmailerBundle', $bundles)) {
$swiftmailerAdapter = new ChildDefinition('sylius.email_sender.adapter.abstract');
$swiftmailerAdapter->setClass(SwiftMailerAdapter::class);
$swiftmailerAdapter->setArguments([new Reference('mailer'), new Reference('event_dispatcher')]);
$swiftmailerAdapter->setPublic(true);

$container->setDefinition('sylius.email_sender.adapter.swiftmailer', $swiftmailerAdapter);
$defaultSenderAdapter = 'sylius.email_sender.adapter.swiftmailer';
if (isset($mergedConfig['sender_adapter'])) {
$container->setAlias('sylius.email_sender.adapter', $mergedConfig['sender_adapter']);
}

$container->setAlias('sylius.email_sender.adapter', $config['sender_adapter'] ?? $defaultSenderAdapter);
}
if (isset($mergedConfig['renderer_adapter'])) {
$container->setAlias('sylius.email_renderer.adapter', $mergedConfig['renderer_adapter']);
}

private function configureRendererAdapter(ContainerBuilder $container, array $config): void
{
$bundles = (array) $container->getParameter('kernel.bundles');
$container->setParameter('sylius.mailer.sender_name', $mergedConfig['sender']['name']);
$container->setParameter('sylius.mailer.sender_address', $mergedConfig['sender']['address']);

$defaultRendererAdapter = 'sylius.email_renderer.adapter.default';
if (array_key_exists('TwigBundle', $bundles)) {
$twigAdapter = new ChildDefinition('sylius.email_renderer.adapter.abstract');
$twigAdapter->setClass(EmailTwigAdapter::class);
$twigAdapter->setArguments([new Reference('twig'), new Reference('event_dispatcher')]);
$twigAdapter->setPublic(true);
$templates = $mergedConfig['templates'] ?? ['Default' => '@SyliusMailer/default.html.twig'];

$container->setDefinition('sylius.email_renderer.adapter.twig', $twigAdapter);
$defaultRendererAdapter = 'sylius.email_renderer.adapter.twig';
}

$container->setAlias('sylius.email_renderer.adapter', $config['renderer_adapter'] ?? $defaultRendererAdapter);
$container->setParameter('sylius.mailer.emails', $mergedConfig['emails']);
$container->setParameter('sylius.mailer.templates', $templates);
}
}
4 changes: 2 additions & 2 deletions src/Bundle/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

<service id="sylius.email_renderer.adapter.abstract" class="Sylius\Component\Mailer\Renderer\Adapter\AbstractAdapter" abstract="true">
<call method="setEventDispatcher">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="event_dispatcher" on-invalid="ignore" />
</call>
</service>
<service
Expand All @@ -52,7 +52,7 @@

<service id="sylius.email_sender.adapter.abstract" class="Sylius\Component\Mailer\Sender\Adapter\AbstractAdapter" abstract="true">
<call method="setEventDispatcher">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="event_dispatcher" on-invalid="ignore" />
</call>
</service>
<service
Expand Down
4 changes: 2 additions & 2 deletions src/Bundle/Sender/Adapter/DefaultAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public function send(
array $replyTo = []
): void {
throw new \RuntimeException(sprintf(
'You need to configure an adapter to send the email. Take a look at %s (requires "symfony/swiftmailer-bundle" library).',
SwiftMailerAdapter::class
'You need to configure an adapter to send the email. Take a look at %s (requires "symfony/mailer" library).',
SymfonyMailerAdapter::class
));
}
}
9 changes: 9 additions & 0 deletions src/Bundle/Sender/Adapter/SwiftMailerAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
use Sylius\Component\Mailer\SyliusMailerEvents;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
* @deprecated The Swift Mailer integration is deprecated since sylius/mailer-bundle 1.8. Use the Symfony Mailer integration instead.
*/
class SwiftMailerAdapter extends AbstractAdapter
{
/** @var \Swift_Mailer */
Expand All @@ -30,6 +33,12 @@ class SwiftMailerAdapter extends AbstractAdapter

public function __construct(\Swift_Mailer $mailer, ?EventDispatcherInterface $dispatcher = null)
{
trigger_deprecation(
'sylius/mailer-bundle',
'1.8',
'The Swift Mailer integration is deprecated and will be removed in 2.0. Use the Symfony Mailer integration instead.'
);

$this->mailer = $mailer;
$this->dispatcher = $dispatcher;
}
Expand Down
66 changes: 66 additions & 0 deletions src/Bundle/Sender/Adapter/SymfonyMailerAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\MailerBundle\Sender\Adapter;

use Sylius\Component\Mailer\Event\EmailSendEvent;
use Sylius\Component\Mailer\Model\EmailInterface;
use Sylius\Component\Mailer\Renderer\RenderedEmail;
use Sylius\Component\Mailer\Sender\Adapter\AbstractAdapter;
use Sylius\Component\Mailer\SyliusMailerEvents;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;

final class SymfonyMailerAdapter extends AbstractAdapter
{
private MailerInterface $mailer;

public function __construct(MailerInterface $mailer)
{
$this->mailer = $mailer;
}

/**
* {@inheritdoc}
*/
public function send(
array $recipients,
string $senderAddress,
string $senderName,
RenderedEmail $renderedEmail,
EmailInterface $email,
array $data,
array $attachments = [],
array $replyTo = []
): void {
$message = (new Email())
->subject($renderedEmail->getSubject())
->from(new Address($senderAddress, $senderName))
->to(...$recipients)
->replyTo(...$replyTo)
->html($renderedEmail->getBody());

foreach ($attachments as $attachment) {
$message->attachFromPath($attachment);
}

$emailSendEvent = new EmailSendEvent($message, $email, $data, $recipients, $replyTo);

$this->dispatcher?->dispatch($emailSendEvent, SyliusMailerEvents::EMAIL_PRE_SEND);

$this->mailer->send($message);

$this->dispatcher?->dispatch($emailSendEvent, SyliusMailerEvents::EMAIL_POST_SEND);
}
}
10 changes: 10 additions & 0 deletions src/Bundle/SyliusMailerBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,18 @@

namespace Sylius\Bundle\MailerBundle;

use Sylius\Bundle\MailerBundle\DependencyInjection\Compiler\RegisterRendererAdapterPass;
use Sylius\Bundle\MailerBundle\DependencyInjection\Compiler\RegisterSenderAdapterPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

final class SyliusMailerBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
parent::build($container);

$container->addCompilerPass(new RegisterRendererAdapterPass());
$container->addCompilerPass(new RegisterSenderAdapterPass());
}
}
6 changes: 3 additions & 3 deletions src/Bundle/spec/Sender/Adapter/DefaultAdapterSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace spec\Sylius\Bundle\MailerBundle\Sender\Adapter;

use PhpSpec\ObjectBehavior;
use Sylius\Bundle\MailerBundle\Sender\Adapter\SwiftMailerAdapter;
use Sylius\Bundle\MailerBundle\Sender\Adapter\SymfonyMailerAdapter;
use Sylius\Component\Mailer\Model\EmailInterface;
use Sylius\Component\Mailer\Renderer\RenderedEmail;
use Sylius\Component\Mailer\Sender\Adapter\AbstractAdapter;
Expand All @@ -32,8 +32,8 @@ function it_throws_an_exception_about_not_configured_email_sender_adapter(
): void {
$this
->shouldThrow(new \RuntimeException(sprintf(
'You need to configure an adapter to send the email. Take a look at %s (requires "symfony/swiftmailer-bundle" library).',
SwiftMailerAdapter::class
'You need to configure an adapter to send the email. Take a look at %s (requires "symfony/mailer" library).',
SymfonyMailerAdapter::class
)))
->during('send', [['[email protected]'], '[email protected]', 'arnaud', $renderedEmail, $email, []])
;
Expand Down
Loading

0 comments on commit ad5eaf1

Please sign in to comment.