Skip to content

Commit

Permalink
feature #47075 [Mime] Change the way we avoid rendering an email twic…
Browse files Browse the repository at this point in the history
…e (fabpot)

This PR was merged into the 6.2 branch.

Discussion
----------

[Mime] Change the way we avoid rendering an email twice

| Q             | A
| ------------- | ---
| Branch?       | 6.2
| Bug fix?      | yes-ish
| New feature?  | yes-ish <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | n/a <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT
| Doc PR        | symfony/symfony-docs#17065

Trying to kill several birds with one stone here.

I was not very happy with the way we ensured that emails were not renderer more than once.
This solution seems easier and allows for people to render an email **before** sending it to Messenger (important when you have Doctrine entities in the context for instance) as documented in the related doc PR.

Commits
-------

cc3b871 [Mime] Change the way we avoid rendering an email twice
  • Loading branch information
fabpot committed Jul 27, 2022
2 parents 41dfb72 + cc3b871 commit 7940cc4
Showing 1 changed file with 8 additions and 24 deletions.
32 changes: 8 additions & 24 deletions src/Symfony/Bridge/Twig/Mime/BodyRenderer.php
Expand Up @@ -45,15 +45,13 @@ public function render(Message $message): void
return;
}

$messageContext = $message->getContext();

$previousRenderingKey = $messageContext[__CLASS__] ?? null;
unset($messageContext[__CLASS__]);
$currentRenderingKey = $this->getFingerPrint($message);
if ($previousRenderingKey === $currentRenderingKey) {
if (null === $message->getTextTemplate() && null === $message->getHtmlTemplate()) {
// email has already been rendered
return;
}

$messageContext = $message->getContext();

if (isset($messageContext['email'])) {
throw new InvalidArgumentException(sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', get_debug_type($message)));
}
Expand All @@ -64,34 +62,20 @@ public function render(Message $message): void

if ($template = $message->getTextTemplate()) {
$message->text($this->twig->render($template, $vars));
$message->textTemplate(null);
}

if ($template = $message->getHtmlTemplate()) {
$message->html($this->twig->render($template, $vars));
$message->htmlTemplate(null);
}

$message->context([]);

// if text body is empty, compute one from the HTML body
if (!$message->getTextBody() && null !== $html = $message->getHtmlBody()) {
$message->text($this->convertHtmlToText(\is_resource($html) ? stream_get_contents($html) : $html));
}
$message->context($message->getContext() + [__CLASS__ => $currentRenderingKey]);
}

private function getFingerPrint(TemplatedEmail $message): string
{
$messageContext = $message->getContext();
unset($messageContext[__CLASS__]);

$payload = [$messageContext, $message->getTextTemplate(), $message->getHtmlTemplate()];
try {
$serialized = serialize($payload);
} catch (\Exception) {
// Serialization of 'Closure' is not allowed
// Happens when context contain a closure, in that case, we assume that context always change.
$serialized = random_bytes(8);
}

return md5($serialized);
}

private function convertHtmlToText(string $html): string
Expand Down

0 comments on commit 7940cc4

Please sign in to comment.