diff --git a/src/BaseEmailInterface.php b/src/BaseEmailInterface.php index f9366c0daa44a5bea9a966265adfe9aa023cb2dc..d8adde5f0ad4a524d047ea874b0c10fa29d2e565 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 6548579d2caeae43e53034a91ee2ebadffc1645f..9f574ddb5a05c94f2bfbf82101b8f32dabfc18b0 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 c5d27f9aa4094c78cf95a85acb547347d5609c9f..d661115d08988f6d0597d9107e5df362c9faa7f0 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 53e6be021d9cc4208c77b3c52ea14b3ba8dc7084..77729557f50d2f7a0bade93f1bbe1908538841b1 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 a7e9521df669491388673be7612f67bcab7c3ec7..2a78c56b766089214f43175490ecfb79fc2e285d 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 fa994824d134af5320f119bb5ca48d6d223b9109..38289f99a2feefd68138ddebf4d4d87b3f4c2ffe 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 62644c50b2067d5d9a3046827cebd994c0be7bae..24d61d50e04fea794c48a44c8ef81000cffdca54 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 45daf52e761930bf58c38c24f4e0ba48cbf2db28..4e2d045bbecf27eb975bb6f6c5f2a9492bca3e1b 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 adba1243c35e36cdcd7ce77c4294351ddbed3891..6945502a1588cd6a0cd5b75ac12737bfcf01941b 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 9a2fd3832d876f24f1adad8b754760a1071cf154..4538eb856244d9b20996a787f23ad7924c783984 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 a5c587748574891257221af36f80bb526939060e..3466d3745f794aaa67bc817c4ee2c9e3e121fccd 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 dc30d9dc96bea86b40cab4fd3593d14b0b86ca3c..e932dcc16463ecd8246a25e014010e7d77dd1cc6 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 cfe93903f99ad80c00b56319066bafd0fa150f62..d5fdda7810836aff9b99ff50a090d4553fcd7041 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 74d9138aa92523306be8103b1a56479a47ec91b0..f46d7a079e98de94db8793db659f787d138ed95e 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 30c22dd626fb6c9a9e2b168d2b7e2d660a0c8c67..a47b132434b8837668e7a738b5b484655caa1401 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 3e76849438a8e28fc975a416ba8d6bbd9dbef0c9..12a2cefca1e3300e1247bf1028adcb3af03fdef5 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 c59b7c27bacd9a6422e3d43f4a010a36d6de8b2a..15e6026e18e980ff3d471d14a6a60a9a0689c54a 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 137d04631ac679dbfef8a81d3a34325eac213ac1..f3dc2bd61fc4c23128943d8fb69878d2ae9f6948 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 a73455cf7cc9b665c7dfb54eeea950f24be5d0b1..c6efee5eec1ea9c985f4ff9bbf67e5f085fdb551 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 ab753e381ec713520ba84f689ca8f7fac9299b90..0524bff0e085aa668dc156d07ee759118283c911 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 8a699dd61d0750f16da4835398118d5777d2002e..7442cd1861dc1ce376ecf82cb162abf83bbed9e4 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 9e1c992bda60cde39b88772dabfbeab0014d0e1d..cd85b538b764e71bc68cd13af2ebc18139a2376d 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 93b0537b404833515939ace23f3fb260358369a9..2c43653ae3583d25ae8912cb27c679480839e8f4 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 5113ed37eb05b87c34b36ec54de2bad5a100cbd6..51de2630ce8d26d87bc767ebc0d819f6a9c2065f 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 47bff6c43478619d91c139c7d09fa8259e384cca..12269547b75d47c840117549d7708735e3c00ab3 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')); }