Skip to content
Snippets Groups Projects
Commit f1066b11 authored by dpi's avatar dpi Committed by Wayne Eaker
Browse files

Issue #3409475: Add Symfony Messenger support for async messages (emails as queues)

parent 5e67813a
No related branches found
No related tags found
1 merge request!7Symfony Messenger integration
......@@ -15,24 +15,25 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Mail\MailInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\mailsystem\MailsystemManager;
use Drupal\symfony_mailer_lite\EmbeddedImage;
use Drupal\symfony_mailer_lite\EmbeddedImageValidatorInterface;
use Html2Text\Html2Text;
use Psr\Log\LoggerInterface;
use stdClass;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Part\DataPart;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\mailsystem\MailsystemManager;
use Symfony\Component\Mime\Email;
/**
* Provides a 'Drupal Symfony Mailer Lite' plugin to send emails.
......@@ -128,6 +129,11 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
*/
protected $embeddedImageValidator;
/**
* @var \Symfony\Component\Mailer\MailerInterface
*/
private MailerInterface $mailer;
/**
* @param EntityTypeManagerInterface $entity_type_manager
* @param ConfigFactoryInterface $config_factory
......@@ -141,7 +147,7 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
* @param $mime_type_guesser
* @param AssetOptimizerInterface|null $cssOptimizer
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, LoggerInterface $logger, RendererInterface $renderer, ModuleHandlerInterface $module_handler, MailManagerInterface $mail_manager, ThemeManagerInterface $theme_manager, AssetResolverInterface $asset_resolver, EmbeddedImageValidatorInterface $embedded_image_validator, AssetOptimizerInterface $cssOptimizer = NULL) {
public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, LoggerInterface $logger, RendererInterface $renderer, ModuleHandlerInterface $module_handler, MailManagerInterface $mail_manager, ThemeManagerInterface $theme_manager, AssetResolverInterface $asset_resolver, EmbeddedImageValidatorInterface $embedded_image_validator, MailerInterface $mailer, AssetOptimizerInterface $cssOptimizer = NULL) {
$this->entityTypeManager = $entity_type_manager;
$this->configFactory = $config_factory;
$this->logger = $logger;
......@@ -153,6 +159,7 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
$this->cssInliner = new CssToInlineStyles();
$this->cssOptimizer = $cssOptimizer;
$this->embeddedImageValidator = $embedded_image_validator;
$this->mailer = $mailer;
}
/**
......@@ -169,7 +176,8 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
$container->get('theme.manager'),
$container->get('asset.resolver'),
$container->get('symfony_mailer_lite.embedded_image_validator'),
$container->get('asset.css.optimizer')
$container->get('symfony_mailer_lite.mailer'),
$container->get('asset.css.optimizer'),
);
}
......@@ -244,18 +252,15 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
* TRUE if the message was successfully sent, and otherwise FALSE.
*/
public function mail(array $message) {
if (!empty($message['symfony_mailer_lite_transport'])) {
$transport_id = $message['symfony_mailer_lite_transport'];
}
else {
$transport_id = $this->configFactory->get('symfony_mailer_lite.settings')->get('default_transport');
}
$transport_entity = \Drupal::entityTypeManager()->getStorage('symfony_mailer_lite_transport')->load($transport_id);
$transport = \Symfony\Component\Mailer\Transport::fromDsn($transport_entity->getDsn());
$mailer = new \Symfony\Component\Mailer\Mailer($transport, NULL, NULL);
try {
$email = new Email();
$customTransport = $message['symfony_mailer_lite_transport'] ?? NULL;
if ($customTransport !== NULL) {
// https://symfony.com/doc/current/mailer.html#multiple-email-transports
$email->getHeaders()->addTextHeader('X-Transport', $customTransport);
}
if (!empty($message['subject'])) {
$email->subject($message['subject']);
}
......@@ -387,7 +392,7 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
}
// Send the message.
$mailer->send($email);
$this->mailer->send($email);
return TRUE;
}
catch (TransportExceptionInterface $e) {
......
<?php
declare(strict_types = 1);
namespace Drupal\symfony_mailer_lite;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Transport\Transports;
/**
* Repository of mailer transport DSNs.
*/
final class TransportsFactory {
/**
* @var ConfigFactoryInterface
*/
protected ConfigFactoryInterface $configFactory;
/**
* @var EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* Constructs a new TransportsFactory.
*/
public function __construct(ConfigFactoryInterface $configFactory, EntityTypeManagerInterface $entityTypeManager) {
$this->entityTypeManager = $entityTypeManager;
$this->configFactory = $configFactory;
}
/**
* Get the collection of all transports.
*
* An object must always be returned, even if transport configuration is
* invalid or missing transports.
*/
public function create(): Transports {
/** @var \Drupal\symfony_mailer_lite\Entity\Transport[] $transportConfigs */
$transportConfigs = $this->entityTypeManager->getStorage('symfony_mailer_lite_transport')->loadMultiple();
$transportConfigs = array_filter($transportConfigs, fn (Entity\Transport $transportConfig): bool => $transportConfig->status() === TRUE);
$dsns = array_map(fn (Entity\Transport $transportConfig): string => $transportConfig->getDsn(), $transportConfigs);
// The default transport must always be the first.
// @see \Symfony\Component\Mailer\Transport\Transports::__construct
$defaultTransportId = $this->configFactory->get('symfony_mailer_lite.settings')->get('default_transport');
if (isset($dsns[$defaultTransportId])) {
$defaultDsn = $dsns[$defaultTransportId];
unset($dsns[$defaultTransportId]);
// Unshift the default with key to the front of the DSN list.
$dsns = [$defaultTransportId => $defaultDsn] + $dsns;
}
else {
// If the default transport mapping no longer exists, unset everything
// until a new default transport is created and/or nominated.
$dsns = [];
}
// If nothing was configured, create a null transport.
if (count($dsns) === 0) {
$dsns = [
'null' => 'null://null',
];
}
try {
return Transport::fromDsns($dsns);
}
catch (\Exception $e) {
// A Transports object with at least one transport must be returned.
return Transport::fromDsns([
'null://null',
]);
}
}
}
......@@ -6,3 +6,27 @@ services:
symfony_mailer_lite.embedded_image_validator:
class: Drupal\symfony_mailer_lite\EmbeddedImageValidator
arguments: ['@file_system', '@file.mime_type.guesser']
# Mailer.
symfony_mailer_lite.transports_factory:
class: Drupal\symfony_mailer_lite\TransportsFactory
arguments: [ '@config.factory', '@entity_type.manager' ]
public: false
symfony_mailer_lite.transports:
class: Symfony\Component\Mailer\Transport\Transports
factory: [ '@symfony_mailer_lite.transports_factory', 'create' ]
public: false
symfony_mailer_lite.mailer:
class: Symfony\Component\Mailer\Mailer
arguments: [ '@symfony_mailer_lite.transports', '@?messenger.default_bus', '@event_dispatcher' ]
Symfony\Component\Mailer\MailerInterface: '@symfony_mailer_lite.mailer'
# Optional messenger integration.
mailer.messenger.message_handler:
class: Symfony\Component\Mailer\Messenger\MessageHandler
arguments: ['@symfony_mailer_lite.transports']
tags:
- { name: messenger.message_handler }
public: false
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment