From a8fa04e0af942217a011e27f99dc04bbdc81f7f9 Mon Sep 17 00:00:00 2001 From: Adam Shepherd <665-AdamPS@users.noreply.drupalcode.org> Date: Sat, 5 Oct 2024 18:39:37 +0000 Subject: [PATCH] Issue #3421400 by adamps, tomsaw: Change to the phases --- src/BaseEmailInterface.php | 2 +- src/BaseEmailTrait.php | 2 +- src/Email.php | 110 +++++++++++++----- src/EmailFactory.php | 4 +- src/EmailInterface.php | 51 ++++---- src/InternalEmailInterface.php | 11 +- src/LegacyMailerHelper.php | 6 - src/Mailer.php | 23 ++-- src/MailerInterface.php | 11 -- .../EmailAdjuster/HooksEmailAdjuster.php | 33 ++++-- .../EmailAdjuster/ThemeEmailAdjuster.php | 3 +- src/Plugin/EmailAdjuster/ToEmailAdjuster.php | 15 +++ .../CommerceOrderEmailBuilder.php | 15 ++- .../EmailBuilder/ContactEmailBuilder.php | 13 ++- .../EmailBuilder/ContactEmailBuilderBase.php | 12 +- .../EmailBuilder/LegacyEmailBuilder.php | 30 ++--- .../SimplenewsEmailBuilderBase.php | 2 +- src/Plugin/EmailBuilder/TestEmailBuilder.php | 7 +- .../EmailBuilder/UpdateEmailBuilder.php | 21 +--- src/Plugin/EmailBuilder/UserEmailBuilder.php | 8 +- src/Processor/EmailAdjusterManager.php | 2 +- src/Processor/EmailProcessorInterface.php | 29 +---- src/Processor/EmailProcessorTrait.php | 9 -- symfony_mailer.api.php | 6 +- .../symfony_mailer_test.module | 2 +- 25 files changed, 224 insertions(+), 203 deletions(-) diff --git a/src/BaseEmailInterface.php b/src/BaseEmailInterface.php index f9366c0d..d8adde5f 100644 --- a/src/BaseEmailInterface.php +++ b/src/BaseEmailInterface.php @@ -104,7 +104,7 @@ interface BaseEmailInterface { /** * Sets "to" addresses. * - * Valid: build. + * Valid: initialisation. * * @param mixed $addresses * The addresses to set, see Address::convert(). Passing NULL as a value diff --git a/src/BaseEmailTrait.php b/src/BaseEmailTrait.php index 6548579d..9f574ddb 100644 --- a/src/BaseEmailTrait.php +++ b/src/BaseEmailTrait.php @@ -65,7 +65,7 @@ trait BaseEmailTrait { $name = strtolower($name); assert(isset($this->addresses[$name])); if ($name == 'to') { - $this->valid(self::PHASE_BUILD); + $this->valid(self::PHASE_INIT, self::PHASE_INIT); } // Either erasing all addresses or updating them for the specified header. diff --git a/src/Email.php b/src/Email.php index c5d27f9a..d661115d 100644 --- a/src/Email.php +++ b/src/Email.php @@ -12,6 +12,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Theme\ThemeManagerInterface; +use Drupal\symfony_mailer\Processor\EmailProcessorInterface; use Drupal\user\Entity\User; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Mime\Email as SymfonyEmail; @@ -114,6 +115,20 @@ class Email implements InternalEmailInterface { */ protected $processors = []; + /** + * The processors remaining to process in the current phase. + * + * @var array + */ + protected $processorQueue = []; + + /** + * Set to TRUE to re-sort the processor queue. + * + * @var bool + */ + protected $processorSort; + /** * The language code. * @@ -235,21 +250,36 @@ class Email implements InternalEmailInterface { /** * {@inheritdoc} */ - public function addProcessor(callable $function, int $phase = self::PHASE_BUILD, int $weight = self::DEFAULT_WEIGHT, ?string $id = NULL) { + public function addProcessor(EmailProcessorInterface $processor) { $this->valid(self::PHASE_INIT, self::PHASE_INIT); - $this->processors[$phase][] = [ - 'function' => $function, - 'weight' => $weight, - 'id' => $id, - ]; + $this->processors[$processor->getId()] = $processor; + $this->processorQueue[] = $processor; + $this->processorSort = TRUE; + return $this; + } + + /** + * {@inheritdoc} + */ + public function removeProcessor(string $id) { + $this->valid(self::PHASE_INIT, self::PHASE_INIT); + unset($this->processors[$id]); + $this->processorQueue = array_filter($this->processorQueue, fn(EmailProcessorInterface $processor) => ($processor->id() != $id)); return $this; } + /** + * {@inheritdoc} + */ + public function getProcessors() { + return $this->processors; + } + /** * {@inheritdoc} */ public function getLangcode() { - $this->valid(self::PHASE_POST_SEND, self::PHASE_PRE_RENDER); + $this->valid(); return $this->langcode; } @@ -289,7 +319,7 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function send() { - $this->valid(self::PHASE_BUILD); + $this->valid(self::PHASE_INIT, self::PHASE_INIT); return $this->mailer->send($this); } @@ -297,7 +327,7 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function getAccount() { - $this->valid(self::PHASE_POST_SEND, self::PHASE_PRE_RENDER); + $this->valid(); return $this->account; } @@ -305,7 +335,7 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function setBody($body) { - $this->valid(self::PHASE_PRE_RENDER); + $this->valid(self::PHASE_BUILD); $this->body = $body; return $this; } @@ -314,7 +344,7 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function setBodyEntity(EntityInterface $entity, $view_mode = 'full') { - $this->valid(self::PHASE_PRE_RENDER); + $this->valid(self::PHASE_BUILD); $build = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId()) ->view($entity, $view_mode); $this->setBody($build); @@ -325,7 +355,7 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function getBody() { - $this->valid(self::PHASE_PRE_RENDER); + $this->valid(self::PHASE_BUILD); return $this->body; } @@ -417,7 +447,7 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function setTheme(string $theme_name) { - $this->valid(self::PHASE_BUILD); + $this->valid(self::PHASE_INIT, self::PHASE_INIT); $this->theme = $theme_name; return $this; } @@ -482,24 +512,40 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function process() { - $processors = $this->processors[$this->phase] ?? []; - usort($processors, function ($a, $b) { - return $a['weight'] <=> $b['weight']; - }); + $this->processorQueue = $this->getProcessors(); + $this->processorSort = TRUE; + + // While processing PHASE_INIT, each processor may add or remove others. + // Therefore we use a queue and a while loop rather than a for loop. + while ($this->processorQueue) { + if ($this->processorSort) { + usort($this->processorQueue, function ($a, $b) { + return $a->getWeight($this->phase) <=> $b->getWeight($this->phase); + }); + $this->processorSort = FALSE; + } - foreach ($processors as $processor) { - call_user_func($processor['function'], $this); - } + $processor = array_shift($this->processorQueue); - return $this; - } + switch ($this->phase) { + case self::PHASE_INIT: + $processor->init($this); + break; + + case self::PHASE_BUILD: + $processor->build($this); + break; + + case self::PHASE_POST_RENDER: + $processor->postRender($this); + break; + + case self::PHASE_POST_SEND: + $processor->postSend($this); + break; + } + } - /** - * {@inheritdoc} - */ - public function initDone() { - $this->valid(self::PHASE_INIT, self::PHASE_INIT); - $this->phase = self::PHASE_BUILD; return $this; } @@ -507,10 +553,10 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function customize(string $langcode, AccountInterface $account) { - $this->valid(self::PHASE_BUILD); + $this->valid(self::PHASE_INIT, self::PHASE_INIT); $this->langcode = $langcode; $this->account = $account; - $this->phase = self::PHASE_PRE_RENDER; + $this->phase = self::PHASE_BUILD; return $this; } @@ -518,7 +564,7 @@ class Email implements InternalEmailInterface { * {@inheritdoc} */ public function render() { - $this->valid(self::PHASE_PRE_RENDER, self::PHASE_PRE_RENDER); + $this->valid(self::PHASE_BUILD, self::PHASE_BUILD); // Render subject. if ($this->subjectReplace && $this->variables) { @@ -616,7 +662,7 @@ class Email implements InternalEmailInterface { * * @return $this */ - protected function valid(int $max_phase, int $min_phase = self::PHASE_BUILD) { + protected function valid(int $max_phase = self::PHASE_POST_SEND, int $min_phase = self::PHASE_BUILD) { $valid = ($this->phase <= $max_phase) && ($this->phase >= $min_phase); if (!$valid) { diff --git a/src/EmailFactory.php b/src/EmailFactory.php index 53e6be02..77729557 100644 --- a/src/EmailFactory.php +++ b/src/EmailFactory.php @@ -90,15 +90,13 @@ class EmailFactory implements EmailFactoryInterface { /** @var \Drupal\symfony_mailer\Processor\EmailBuilderInterface $builder */ $builder = $this->emailBuilderManager->createInstance($plugin_id); $builder->createParams($email, ...$params); - $builder->init($email); + $email->addProcessor($builder); break; } } // Apply policy. $this->emailAdjusterManager->applyPolicy($email); - - $email->initDone(); return $email; } diff --git a/src/EmailInterface.php b/src/EmailInterface.php index a7e9521d..2a78c56b 100644 --- a/src/EmailInterface.php +++ b/src/EmailInterface.php @@ -3,6 +3,7 @@ namespace Drupal\symfony_mailer; use Drupal\Core\Entity\EntityInterface; +use Drupal\symfony_mailer\Processor\EmailProcessorInterface; /** * Defines the interface for an Email. @@ -32,16 +33,6 @@ interface EmailInterface extends BaseEmailInterface { */ const PHASE_BUILD = 1; - /** - * Pre-render phase: preparation for rendering. - * - * Not normally needed. Only if there is a rendering step that needs to be - * done before the main rendering call. - * - * @see \Drupal\symfony_mailer\Processor\EmailProcessorInterface::preRender() - */ - const PHASE_PRE_RENDER = 2; - /** * Post-render phase: adjusting of rendered output. * @@ -64,37 +55,47 @@ interface EmailInterface extends BaseEmailInterface { const PHASE_NAMES = [ self::PHASE_INIT => 'init', self::PHASE_BUILD => 'build', - self::PHASE_PRE_RENDER => 'pre_render', self::PHASE_POST_RENDER => 'post_render', self::PHASE_POST_SEND => 'post_send', ]; /** - * Add an email processor. + * Adds an email processor. + * + * Valid: initialisation. + * + * @param \Drupal\symfony_mailer\Processor\EmailProcessorInterface $processor + * The email processor. + * + * @return $this + */ + public function addProcessor(EmailProcessorInterface $processor); + + /** + * Removes an email processor. * * Valid: initialisation. * - * @param callable $function - * The function to call. - * @param int $phase - * (Optional) The phase to run in, one of the EmailInterface::PHASE_ - * constants. - * @param int $weight - * (Optional) The weight, lower values run earlier. * @param string $id - * (Optional) An ID that can be used to alter or debug. + * The email processor ID. * * @return $this */ - public function addProcessor(callable $function, int $phase = self::PHASE_BUILD, int $weight = self::DEFAULT_WEIGHT, ?string $id = NULL); + public function removeProcessor(string $id); + + /** + * Gets the email processors. + * + * @return \Drupal\symfony_mailer\Processor\EmailProcessorInterface[] + * The processors. + */ + public function getProcessors(); /** * Gets the langcode. * * The langcode is calculated automatically from the to address. * - * Valid: after rendering. - * * @return string * Language code to use to compose the email. */ @@ -163,8 +164,6 @@ interface EmailInterface extends BaseEmailInterface { * * The account is calculated automatically from the to address. * - * Valid: after rendering. - * * @return \Drupal\Core\Session\AccountInterface * The account. */ @@ -318,7 +317,7 @@ interface EmailInterface extends BaseEmailInterface { /** * Sets the email theme. * - * Valid: build. + * Valid: initialisation. * * @param string $theme_name * The theme name to use for email. diff --git a/src/InternalEmailInterface.php b/src/InternalEmailInterface.php index fa994824..38289f99 100644 --- a/src/InternalEmailInterface.php +++ b/src/InternalEmailInterface.php @@ -18,19 +18,10 @@ interface InternalEmailInterface extends EmailInterface { */ public function process(); - /** - * Ends the initialization phase. - * - * Valid: initialisation. - * - * @return $this - */ - public function initDone(); - /** * Customizes the email. * - * Valid: before rendering. + * Valid: initialisation. * * @param string $langcode * The language code. diff --git a/src/LegacyMailerHelper.php b/src/LegacyMailerHelper.php index 62644c50..24d61d50 100644 --- a/src/LegacyMailerHelper.php +++ b/src/LegacyMailerHelper.php @@ -125,12 +125,6 @@ class LegacyMailerHelper implements LegacyMailerHelperInterface { $src_headers = $message['headers']; $dest_headers = $email->getHeaders(); - // Add in 'To' header which is stored directly in the message. - // @see \Drupal\Core\Mail\Plugin\Mail\PhpMail::mail() - if (isset($message['to'])) { - $src_headers['to'] = $message['to']; - } - foreach ($src_headers as $name => $value) { $name = strtolower($name); if (isset(self::SKIP_HEADERS[$name])) { diff --git a/src/Mailer.php b/src/Mailer.php index 45daf52e..4e2d045b 100644 --- a/src/Mailer.php +++ b/src/Mailer.php @@ -170,15 +170,11 @@ class Mailer implements MailerInterface { * @internal */ public function doSend(InternalEmailInterface $email) { - // LegacyEmailBuilder sets the theme during the process phase. Save the - // active theme so we can change back. - $active_theme_name = $this->themeManager->getActiveTheme()->getName(); - - // Process the build phase. - // @see \Drupal\symfony_mailer\EmailInterface::PHASE_BUILD + // Process the init phase. + // @see \Drupal\symfony_mailer\EmailInterface::PHASE_INIT $email->process(); - // Do switching. + // Calculate required switching. $current_langcode = $this->languageManager->getCurrentLanguage()->getId(); if ($email->getParam('__disable_customize__')) { // Undocumented setting for use from LegacyEmailBuilder only for @@ -193,8 +189,6 @@ class Mailer implements MailerInterface { $account = $this->account; } else { - $this->changeTheme($email->getTheme()); - // Determine langcode and account from the to address, if there is // agreement. $langcodes = $accounts = []; @@ -212,21 +206,22 @@ class Mailer implements MailerInterface { $email->customize($langcode, $account); - $must_switch_account = $account->id() != $this->account->id(); + // Do switching. + $active_theme_name = $this->changeTheme($email->getTheme()); + $must_switch_account = $account->id() != $this->account->id(); if ($must_switch_account) { $this->accountSwitcher->switchTo($account); } $must_switch_language = $langcode !== $current_langcode; - if ($must_switch_language) { $this->changeActiveLanguage($langcode); } try { - // Process the pre-render phase. - // @see \Drupal\symfony_mailer\EmailInterface::PHASE_PRE_RENDER + // Process the build phase. + // @see \Drupal\symfony_mailer\EmailInterface::PHASE_BUILD $email->process(); // Render. @@ -299,7 +294,7 @@ class Mailer implements MailerInterface { /** * {@inheritdoc} */ - public function changeTheme(string $theme_name) { + protected function changeTheme(string $theme_name) { $active_theme_name = $this->themeManager->getActiveTheme()->getName(); if ($theme_name !== $active_theme_name) { $this->themeManager->setActiveTheme($this->themeInitialization->initTheme($theme_name)); diff --git a/src/MailerInterface.php b/src/MailerInterface.php index adba1243..6945502a 100644 --- a/src/MailerInterface.php +++ b/src/MailerInterface.php @@ -18,15 +18,4 @@ interface MailerInterface { */ public function send(InternalEmailInterface $email); - /** - * Changes the active theme. - * - * @param string $theme_name - * The theme name. - * - * @return string - * The previously active theme name. - */ - public function changeTheme(string $theme_name); - } diff --git a/src/Plugin/EmailAdjuster/HooksEmailAdjuster.php b/src/Plugin/EmailAdjuster/HooksEmailAdjuster.php index 9a2fd383..4538eb85 100644 --- a/src/Plugin/EmailAdjuster/HooksEmailAdjuster.php +++ b/src/Plugin/EmailAdjuster/HooksEmailAdjuster.php @@ -29,17 +29,28 @@ class HooksEmailAdjuster extends EmailAdjusterBase { */ public function init(EmailInterface $email) { $this->moduleHandler = \Drupal::moduleHandler(); + $this->invokeHooks($email); + } - foreach (EmailInterface::PHASE_NAMES as $phase => $name) { - if ($phase == EmailInterface::PHASE_INIT) { - // Call init hooks immediately. - $this->invokeHooks($email); - } - else { - // Add processor to invoke hooks later. - $email->addProcessor([$this, 'invokeHooks'], $phase, EmailInterface::DEFAULT_WEIGHT, "hook_mailer_$name"); - } - } + /** + * {@inheritdoc} + */ + public function build(EmailInterface $email) { + $this->invokeHooks($email); + } + + /** + * {@inheritdoc} + */ + public function postRender(EmailInterface $email) { + $this->invokeHooks($email); + } + + /** + * {@inheritdoc} + */ + public function postSend(EmailInterface $email) { + $this->invokeHooks($email); } /** @@ -52,7 +63,7 @@ class HooksEmailAdjuster extends EmailAdjusterBase { * @see hook_mailer_TYPE_PHASE() * @see hook_mailer_TYPE__SUBTYPE_PHASE() */ - public function invokeHooks(EmailInterface $email) { + protected function invokeHooks(EmailInterface $email) { $name = EmailInterface::PHASE_NAMES[$email->getPhase()]; $type = $email->getType(); $sub_type = $email->getSubType(); diff --git a/src/Plugin/EmailAdjuster/ThemeEmailAdjuster.php b/src/Plugin/EmailAdjuster/ThemeEmailAdjuster.php index a5c58774..3466d374 100644 --- a/src/Plugin/EmailAdjuster/ThemeEmailAdjuster.php +++ b/src/Plugin/EmailAdjuster/ThemeEmailAdjuster.php @@ -18,7 +18,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * id = "email_theme", * label = @Translation("Theme"), * description = @Translation("Sets the email theme."), - * weight = 0, * ) */ class ThemeEmailAdjuster extends EmailAdjusterBase implements ContainerFactoryPluginInterface { @@ -86,7 +85,7 @@ class ThemeEmailAdjuster extends EmailAdjusterBase implements ContainerFactoryPl /** * {@inheritdoc} */ - public function build(EmailInterface $email) { + public function init(EmailInterface $email) { $theme_name = $this->getEmailTheme(); $email->setTheme($theme_name); } diff --git a/src/Plugin/EmailAdjuster/ToEmailAdjuster.php b/src/Plugin/EmailAdjuster/ToEmailAdjuster.php index dc30d9dc..e932dcc1 100644 --- a/src/Plugin/EmailAdjuster/ToEmailAdjuster.php +++ b/src/Plugin/EmailAdjuster/ToEmailAdjuster.php @@ -2,6 +2,8 @@ namespace Drupal\symfony_mailer\Plugin\EmailAdjuster; +use Drupal\symfony_mailer\EmailInterface; + /** * Defines the To Email Adjuster. * @@ -18,4 +20,17 @@ class ToEmailAdjuster extends AddressAdjusterBase { */ protected const NAME = 'to'; + /** + * {@inheritdoc} + */ + public function init(EmailInterface $email) { + parent::build($email); + } + + /** + * {@inheritdoc} + */ + public function build(EmailInterface $email) { + } + } diff --git a/src/Plugin/EmailBuilder/CommerceOrderEmailBuilder.php b/src/Plugin/EmailBuilder/CommerceOrderEmailBuilder.php index cfe93903..d5fdda78 100644 --- a/src/Plugin/EmailBuilder/CommerceOrderEmailBuilder.php +++ b/src/Plugin/EmailBuilder/CommerceOrderEmailBuilder.php @@ -79,14 +79,21 @@ class CommerceOrderEmailBuilder extends EmailBuilderBase { /** * {@inheritdoc} */ - public function build(EmailInterface $email) { + public function init(EmailInterface $email) { $order = $email->getParam('commerce_order_item'); - $store = $order->getStore(); $customer = $order->getCustomer(); $to = $customer->isAuthenticated() ? $customer : $order->getEmail(); + $email->setTo($to); + } + + /** + * {@inheritdoc} + */ + public function build(EmailInterface $email) { + $order = $email->getParam('commerce_order_item'); + $store = $order->getStore(); - $email->setTo($to) - ->setBodyEntity($order, 'email') + $email->setBodyEntity($order, 'email') ->addLibrary('symfony_mailer/commerce_order') ->setVariable('order_number', $order->getOrderNumber()) ->setVariable('store', $store->getName()); diff --git a/src/Plugin/EmailBuilder/ContactEmailBuilder.php b/src/Plugin/EmailBuilder/ContactEmailBuilder.php index 74d9138a..f46d7a07 100644 --- a/src/Plugin/EmailBuilder/ContactEmailBuilder.php +++ b/src/Plugin/EmailBuilder/ContactEmailBuilder.php @@ -55,6 +55,15 @@ class ContactEmailBuilder extends ContactEmailBuilderBase { return $factory->newTypedEmail('contact', $key, $contact_message, $sender, $message['params']['recipient']); } + /** + * {@inheritdoc} + */ + public function init(EmailInterface $email) { + if ($email->getSubType() == 'mail') { + $email->setTo($email->getParam('recipient')); + } + } + /** * {@inheritdoc} */ @@ -64,10 +73,6 @@ class ContactEmailBuilder extends ContactEmailBuilderBase { $email->setVariable('recipient_name', $recipient->getDisplayName()) ->setVariable('recipient_edit_url', $recipient->toUrl('edit-form')->toString()); - - if ($email->getSubType() == 'mail') { - $email->setTo($recipient); - } } } diff --git a/src/Plugin/EmailBuilder/ContactEmailBuilderBase.php b/src/Plugin/EmailBuilder/ContactEmailBuilderBase.php index 30c22dd6..a47b1324 100644 --- a/src/Plugin/EmailBuilder/ContactEmailBuilderBase.php +++ b/src/Plugin/EmailBuilder/ContactEmailBuilderBase.php @@ -14,6 +14,15 @@ class ContactEmailBuilderBase extends EmailBuilderBase { use MailerHelperTrait; + /** + * {@inheritdoc} + */ + public function init(EmailInterface $email) { + if ($email->getSubType() != 'mail') { + $email->setTo($email->getParam('sender')); + } + } + /** * {@inheritdoc} */ @@ -32,9 +41,6 @@ class ContactEmailBuilderBase extends EmailBuilderBase { if ($email->getSubType() == 'mail') { $email->setReplyTo($sender); } - else { - $email->setTo($sender); - } } } diff --git a/src/Plugin/EmailBuilder/LegacyEmailBuilder.php b/src/Plugin/EmailBuilder/LegacyEmailBuilder.php index 3e768494..12a2cefc 100644 --- a/src/Plugin/EmailBuilder/LegacyEmailBuilder.php +++ b/src/Plugin/EmailBuilder/LegacyEmailBuilder.php @@ -8,6 +8,7 @@ use Drupal\symfony_mailer\EmailFactoryInterface; use Drupal\symfony_mailer\EmailInterface; use Drupal\symfony_mailer\Exception\SkipMailException; use Drupal\symfony_mailer\LegacyMailerHelperInterface; +use Drupal\symfony_mailer\MailerHelperTrait; use Drupal\symfony_mailer\MailerInterface; use Drupal\symfony_mailer\Processor\EmailBuilderBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -17,6 +18,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class LegacyEmailBuilder extends EmailBuilderBase implements ContainerFactoryPluginInterface { + use MailerHelperTrait; + /** * The legacy mailer helper. * @@ -98,6 +101,18 @@ class LegacyEmailBuilder extends EmailBuilderBase implements ContainerFactoryPlu ->setParam('__disable_customize__', TRUE); } + /** + * {@inheritdoc} + */ + public function init(EmailInterface $email) { + // Add in 'To' header which is stored directly in the message. + // @see \Drupal\Core\Mail\Plugin\Mail\PhpMail::mail() + $message = $email->getParam('legacy_message'); + if (isset($message['to'])) { + $email->setTo($this->helper()->parseAddress($message['to'])); + } + } + /** * {@inheritdoc} */ @@ -114,11 +129,6 @@ class LegacyEmailBuilder extends EmailBuilderBase implements ContainerFactoryPlu $message['headers']['Reply-to'] = $reply; } - // Force changing theme early to ensure that hook_mail() is called with the - // correct theme. The mailer will restore the original theme. - $this->theme = $email->getTheme(); - $this->mailer->changeTheme($this->theme); - // Build the email by invoking hook_mail() on this module. $args = [$message['key'], &$message, $message['params']]; $this->moduleHandler->invoke($message['module'], 'mail', $args); @@ -136,14 +146,4 @@ class LegacyEmailBuilder extends EmailBuilderBase implements ContainerFactoryPlu $this->legacyHelper->emailFromArray($email, $message); } - /** - * {@inheritdoc} - */ - public function preRender(EmailInterface $email) { - // Check the theme wasn't changed after our build() function ran. - if ($this->theme != $email->getTheme()) { - throw new \Exception("Mail theme changed after rendering legacy Email"); - } - } - } diff --git a/src/Plugin/EmailBuilder/SimplenewsEmailBuilderBase.php b/src/Plugin/EmailBuilder/SimplenewsEmailBuilderBase.php index c59b7c27..15e6026e 100644 --- a/src/Plugin/EmailBuilder/SimplenewsEmailBuilderBase.php +++ b/src/Plugin/EmailBuilder/SimplenewsEmailBuilderBase.php @@ -19,7 +19,7 @@ class SimplenewsEmailBuilderBase extends EmailBuilderBase { /** * {@inheritdoc} */ - public function build(EmailInterface $email) { + public function init(EmailInterface $email) { // @todo Add a method SubscriberInterface::getAddress(). $subscriber = $email->getParam('simplenews_subscriber'); $address = new Address($subscriber->getMail(), NULL, $subscriber->getLangcode(), $subscriber->getUser()); diff --git a/src/Plugin/EmailBuilder/TestEmailBuilder.php b/src/Plugin/EmailBuilder/TestEmailBuilder.php index 137d0463..f3dc2bd6 100644 --- a/src/Plugin/EmailBuilder/TestEmailBuilder.php +++ b/src/Plugin/EmailBuilder/TestEmailBuilder.php @@ -38,11 +38,16 @@ class TestEmailBuilder extends EmailBuilderBase { /** * {@inheritdoc} */ - public function build(EmailInterface $email) { + public function init(EmailInterface $email) { if ($to = $email->getParam('to')) { $email->setTo($to); } + } + /** + * {@inheritdoc} + */ + public function build(EmailInterface $email) { $logo = \Drupal::service('extension.list.module')->getPath('symfony_mailer') . '/logo.png'; $logo_uri = \Drupal::service('file_url_generator')->generateString($logo); diff --git a/src/Plugin/EmailBuilder/UpdateEmailBuilder.php b/src/Plugin/EmailBuilder/UpdateEmailBuilder.php index a73455cf..c6efee5e 100644 --- a/src/Plugin/EmailBuilder/UpdateEmailBuilder.php +++ b/src/Plugin/EmailBuilder/UpdateEmailBuilder.php @@ -54,6 +54,10 @@ class UpdateEmailBuilder extends EmailBuilderBase { * {@inheritdoc} */ public function build(EmailInterface $email) { + if (empty($email->getTo())) { + throw new SkipMailException('No update notification address configured.'); + } + $config = $this->helper()->config(); $notify_all = ($config->get('update.settings')->get('notification.threshold') == 'all'); \Drupal::moduleHandler()->loadInclude('update', 'install'); @@ -80,23 +84,6 @@ class UpdateEmailBuilder extends EmailBuilderBase { } } - /** - * Skip sending the update email when no 'To' header is configured. - * - * This check has to be done after - * {@see \Drupal\symfony_mailer\EmailInterface::PHASE_BUILD} because - * otherwise the 'To' header might not be set yet. - * - * @throws \Drupal\symfony_mailer\Exception\SkipMailException - * - * @see \Drupal\symfony_mailer\EmailInterface::PHASE_PRE_RENDER - */ - public function preRender(EmailInterface $email): void { - if (empty($email->getTo())) { - throw new SkipMailException('No update notification address configured.'); - } - } - /** * {@inheritdoc} */ diff --git a/src/Plugin/EmailBuilder/UserEmailBuilder.php b/src/Plugin/EmailBuilder/UserEmailBuilder.php index ab753e38..0524bff0 100644 --- a/src/Plugin/EmailBuilder/UserEmailBuilder.php +++ b/src/Plugin/EmailBuilder/UserEmailBuilder.php @@ -94,10 +94,16 @@ class UserEmailBuilder extends EmailBuilderBase { /** * {@inheritdoc} */ - public function build(EmailInterface $email) { + public function init(EmailInterface $email) { if ($email->getSubType() != 'register_pending_approval_admin') { $email->setTo($email->getParam('user')); } + } + + /** + * {@inheritdoc} + */ + public function build(EmailInterface $email) { $this->tokenOptions(['callback' => 'user_mail_tokens', 'clear' => TRUE]); } diff --git a/src/Processor/EmailAdjusterManager.php b/src/Processor/EmailAdjusterManager.php index 8a699dd6..7442cd18 100644 --- a/src/Processor/EmailAdjusterManager.php +++ b/src/Processor/EmailAdjusterManager.php @@ -47,7 +47,7 @@ class EmailAdjusterManager extends DefaultPluginManager implements EmailAdjuster // Add adjusters. foreach ($policy_config as $plugin_id => $config) { if ($this->hasDefinition($plugin_id)) { - $this->createInstance($plugin_id, $config)->init($email); + $email->addProcessor($this->createInstance($plugin_id, $config)); } } } diff --git a/src/Processor/EmailProcessorInterface.php b/src/Processor/EmailProcessorInterface.php index 9e1c992b..cd85b538 100644 --- a/src/Processor/EmailProcessorInterface.php +++ b/src/Processor/EmailProcessorInterface.php @@ -10,19 +10,7 @@ use Drupal\symfony_mailer\EmailInterface; interface EmailProcessorInterface { /** - * Mapping from phase to default function name. - * - * @var string[] - */ - public const FUNCTION_NAMES = [ - EmailInterface::PHASE_BUILD => 'build', - EmailInterface::PHASE_PRE_RENDER => 'preRender', - EmailInterface::PHASE_POST_RENDER => 'postRender', - EmailInterface::PHASE_POST_SEND => 'postSend', - ]; - - /** - * Initializes an email to call this email processor. + * Process emails during the initialise phase. * * @param \Drupal\symfony_mailer\EmailInterface $email * The email to initialize. @@ -32,26 +20,13 @@ interface EmailProcessorInterface { /** * Process emails during the build phase. * - * Must not trigger any rendering because cannot yet rely on the correct - * language, theme, and account. For example, must not cast a translatable - * string into a plain string, or replace tokens. + * The language, theme, and account are now correct. * * @param \Drupal\symfony_mailer\EmailInterface $email * The email to process. */ public function build(EmailInterface $email); - /** - * Process emails during the pre-render phase. - * - * Not normally needed. Only if there is a rendering step that needs to be - * done before the main rendering call. - * - * @param \Drupal\symfony_mailer\EmailInterface $email - * The email to process. - */ - public function preRender(EmailInterface $email); - /** * Process emails during the post-render phase. * diff --git a/src/Processor/EmailProcessorTrait.php b/src/Processor/EmailProcessorTrait.php index 93b0537b..2c43653a 100644 --- a/src/Processor/EmailProcessorTrait.php +++ b/src/Processor/EmailProcessorTrait.php @@ -13,9 +13,6 @@ trait EmailProcessorTrait { * {@inheritdoc} */ public function init(EmailInterface $email) { - foreach (self::FUNCTION_NAMES as $phase => $function) { - $email->addProcessor([$this, $function], $phase, $this->getWeight($phase), $this->getId()); - } } /** @@ -24,12 +21,6 @@ trait EmailProcessorTrait { public function build(EmailInterface $email) { } - /** - * {@inheritdoc} - */ - public function preRender(EmailInterface $email) { - } - /** * {@inheritdoc} */ diff --git a/symfony_mailer.api.php b/symfony_mailer.api.php index 5113ed37..51de2630 100644 --- a/symfony_mailer.api.php +++ b/symfony_mailer.api.php @@ -19,12 +19,14 @@ function hook_mailer_PHASE(EmailInterface $email) { // hook_mailer_init(): // - Add a class. // - Re-use an EmailAdjuster. - (new CustomEmailProcessor())->init($email); + $email->addProcessor(new CustomEmailProcessor()); $config = ['message' => 'Unpopular user skipped']; Drupal::service('plugin.manager.email_adjuster')->createInstance('email_skip_sending', $config)->init($email); - // hook_mailer_build(): + // hook_mailer_init(): $email->setTo('user@example.com'); + + // hook_mailer_build(): $body = $email->getBody(); $body['extra'] = ['#markup' => 'Extra text']; $email->setBody($body); diff --git a/tests/modules/symfony_mailer_test/symfony_mailer_test.module b/tests/modules/symfony_mailer_test/symfony_mailer_test.module index 47bff6c4..12269547 100644 --- a/tests/modules/symfony_mailer_test/symfony_mailer_test.module +++ b/tests/modules/symfony_mailer_test/symfony_mailer_test.module @@ -11,5 +11,5 @@ use Drupal\symfony_mailer\EmailInterface; * Implements hook_mailer_init(). */ function symfony_mailer_test_mailer_init(EmailInterface $email) { - \Drupal::service('symfony_mailer.test')->init($email); + $email->addProcessor(\Drupal::service('symfony_mailer.test')); } -- GitLab