From c3e30ebda24d4118dcf8ed931b0f45f76ae1b40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 11 Mar 2021 14:53:29 +0100 Subject: [PATCH] Fix fingerprint when context is not serializable --- src/Symfony/Bridge/Twig/Mime/BodyRenderer.php | 19 ++++++++++++++++- .../Twig/Tests/Mime/BodyRendererTest.php | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php index dfd348937d..166b3c195f 100644 --- a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php +++ b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php @@ -49,7 +49,7 @@ final class BodyRenderer implements BodyRendererInterface $previousRenderingKey = $messageContext[__CLASS__] ?? null; unset($messageContext[__CLASS__]); - $currentRenderingKey = md5(serialize([$messageContext, $message->getTextTemplate(), $message->getHtmlTemplate()])); + $currentRenderingKey = $this->getFingerPrint($message); if ($previousRenderingKey === $currentRenderingKey) { return; } @@ -77,6 +77,23 @@ final class BodyRenderer implements BodyRendererInterface $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 $e) { + // 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 { if (null !== $this->converter) { diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php index f13ab213c3..8ff343b684 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php @@ -100,6 +100,27 @@ HTML; $this->assertEquals('reset', $email->getTextBody()); } + public function testRenderedOnceUnserializableContext() + { + $twig = new Environment(new ArrayLoader([ + 'text' => 'Text', + ])); + $renderer = new BodyRenderer($twig); + $email = (new TemplatedEmail()) + ->to('fabien@symfony.com') + ->from('helene@symfony.com') + ; + $email->textTemplate('text'); + $email->context([ + 'foo' => static function () { + return 'bar'; + }, + ]); + + $renderer->render($email); + $this->assertEquals('Text', $email->getTextBody()); + } + private function prepareEmail(?string $text, ?string $html, array $context = []): TemplatedEmail { $twig = new Environment(new ArrayLoader([