8000 bug #40446 [TwigBridge] Fix "Serialization of 'Closure'" error when r… · symfony/symfony@9f3c30a · GitHub
[go: up one dir, main page]

Skip to content

Commit 9f3c30a

Browse files
committed
bug #40446 [TwigBridge] Fix "Serialization of 'Closure'" error when rendering an TemplatedEmail (jderusse)
This PR was merged into the 4.4 branch. Discussion ---------- [TwigBridge] Fix "Serialization of 'Closure'" error when rendering an TemplatedEmail | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #40445 | License | MIT | Doc PR | When context contains a closure, it can't be serialized. In that case, we now assume that fingerprint is always different, and in that case, email will always be re-rendered Commits ------- c3e30eb Fix fingerprint when context is not serializable
2 parents 756522e + c3e30eb commit 9f3c30a

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

src/Symfony/Bridge/Twig/Mime/BodyRenderer.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function render(Message $message): void
4949

5050
$previousRenderingKey = $messageContext[__CLASS__] ?? null;
5151
unset($messageContext[__CLASS__]);
52-
$currentRenderingKey = md5(serialize([$messageContext, $message->getTextTemplate(), $message->getHtmlTemplate()]));
52+
$currentRenderingKey = $this->getFingerPrint($message);
5353
if ($previousRenderingKey === $currentRenderingKey) {
5454
return;
5555
}
@@ -77,6 +77,23 @@ public function render(Message $message): void
7777
$message->context($message->getContext() + [__CLASS__ => $currentRenderingKey]);
7878
}
7979

80+
private function getFingerPrint(TemplatedEmail $message): string
81+
{
82+
$messageContext = $message->getContext();
83+
unset($messageContext[__CLASS__]);
84+
85+
$payload = [$messageContext, $message->getTextTemplate(), $message->getHtmlTemplate()];
86+
try {
87+
$serialized = serialize($payload);
88+
} catch (\Exception $e) {
89+
// Serialization of 'Closure' is not allowed
90+
// Happens when context contain a closure, in that case, we assume that context always change.
91+
$serialized = random_bytes(8);
92+
}
93+
94+
return md5($serialized);
95+
}
96+
8097
private function convertHtmlToText(string $html): string
8198
{
8299
if (null !== $this->converter) {

src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,27 @@ public function testRenderedOnce()
100100
$this->assertEquals('reset', $email->getTextBody());
101101
}
102102

103+
public function testRenderedOnceUnserializableContext()
104+
{
105+
$twig = new Environment(new ArrayLoader([
106+
'text' => 'Text',
107+
]) A6A5 );
108+
$renderer = new BodyRenderer($twig);
109+
$email = (new TemplatedEmail())
110+
->to('fabien@symfony.com')
111+
->from('helene@symfony.com')
112+
;
113+
$email->textTemplate('text');
114+
$email->context([
115+
'foo' => static function () {
116+
return 'bar';
117+
},
118+
]);
119+
120+
$renderer->render($email);
121+
$this->assertEquals('Text', $email->getTextBody());
122+
}
123+
103124
private function prepareEmail(?string $text, ?string $html, array $context = []): TemplatedEmail
104125
{
105126
$twig = new Environment(new ArrayLoader([

0 commit comments

Comments
 (0)
0