Skip to content

Commit bd8662d

Browse files
committed
[Twig] Add NotificationEmail
1 parent 1efae63 commit bd8662d

File tree

13 files changed

+2100
-15
lines changed

13 files changed

+2100
-15
lines changed

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@
119119
"egulias/email-validator": "~1.2,>=1.2.8|~2.0",
120120
"symfony/phpunit-bridge": "^3.4.31|^4.3.4|~5.0",
121121
"symfony/security-acl": "~2.8|~3.0",
122-
"phpdocumentor/reflection-docblock": "^3.0|^4.0"
122+
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
123+
"twig/cssinliner-extra": "^2.12",
124+
"twig/inky-extra": "^2.12",
125+
"twig/markdown-extra": "^2.12"
123126
},
124127
"conflict": {
125128
"masterminds/html5": "<2.6",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public function render(Message $message): void
4747

4848
$messageContext = $message->getContext();
4949
if (isset($messageContext['email'])) {
50-
throw new InvalidArgumentException(sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', TemplatedEmail::class));
50+
throw new InvalidArgumentException(sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', \get_class($message)));
5151
}
5252

5353
$vars = array_merge($this->context, $messageContext, [
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Twig\Mime;
13+
14+
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
15+
use Symfony\Component\Mime\Header\Headers;
16+
use Symfony\Component\Mime\Part\AbstractPart;
17+
use Twig\Extra\CssInliner\CssInlinerExtension;
18+
use Twig\Extra\Inky\InkyExtension;
19+
use Twig\Extra\Markdown\MarkdownExtension;
20+
21+
/**
22+
* @author Fabien Potencier <fabien@symfony.com>
23+
*/
24+
class NotificationEmail extends TemplatedEmail
25+
{
26+
public const IMPORTANCE_URGENT = 'urgent';
27+
public const IMPORTANCE_HIGH = 'high';
28+
public const IMPORTANCE_MEDIUM = 'medium';
29+
public const IMPORTANCE_LOW = 'low';
30+
31+
private $theme = 'default';
32+
private $context = [
33+
'importance' => self::IMPORTANCE_LOW,
34+
'content' => '',
35+
'exception' => false,
36+
'action_text' => null,
37+
'action_url' => null,
38+
'markdown' => false,
39+
'raw' => false,
40+
];
41+
42+
public function __construct(Headers $headers = null, AbstractPart $body = null)
43+
{
44+
if (!class_exists(CssInlinerExtension::class)) {
45+
throw new \LogicException(sprintf('You cannot use "%s" if the CSS Inliner Twig extension is not available; try running "composer require twig/cssinliner-extra".', static::class));
46+
}
47+
48+
if (!class_exists(InkyExtension::class)) {
49+
throw new \LogicException(sprintf('You cannot use "%s" if the Inky Twig extension is not available; try running "composer require twig/inky-extra".', static::class));
50+
}
51+
52+
parent::__construct($headers, $body);
53+
}
54+
55+
/**
56+
* @return $this
57+
*/
58+
public function markdown()
59+
{
60+
if (!class_exists(MarkdownExtension::class)) {
61+
throw new \LogicException(sprintf('You cannot use "%s" if the Markdown Twig extension is not available; try running "composer require twig/markdown-extra".', __METHOD__));
62+
}
63+
64+
$this->context['markdown'] = true;
65+
66+
return $this;
67+
}
68+
69+
/**
70+
* @return $this
71+
*/
72+
public function content(string $content, bool $raw = false)
73+
{
74+
$this->context['content'] = $content;
75+
$this->context['raw'] = $raw;
76+
77+
return $this;
78+
}
79+
80+
/**
81+
* @return $this
82+
*/
83+
public function action(string $text, string $url)
84+
{
85+
$this->context['action_text'] = $text;
86+
$this->context['action_url'] = $url;
87+
88+
return $this;
89+
}
90+
91+
/**
92+
* @return self
93+
*/
94+
public function importance(string $importance)
95+
{
96+
$this->context['importance'] = $importance;
97+
98+
return $this;
99+
}
100+
101+
/**
102+
* @param \Throwable|FlattenException
103+
*
104+
* @return $this
105+
*/
106+
public function exception($exception)
107+
{
108+
$exceptionAsString = $this->getExceptionAsString($exception);
109+
110+
$this->context['exception'] = true;
111+
$this->attach($exceptionAsString, 'exception.txt', 'text/plain');
112+
$this->importance(self::IMPORTANCE_URGENT);
113+
114+
if (!$this->getSubject()) {
115+
$this->subject($exception->getMessage());
116+
}
117+
118+
return $this;
119+
}
120+
121+
/**
122+
* @return $this
123+
*/
124+
public function theme(string $theme)
125+
{
126+
$this->theme = $theme;
127+
128+
return $this;
129+
}
130+
131+
public function getTextTemplate(): ?string
132+
{
133+
if ($template = parent::getTextTemplate()) {
134+
return $template;
135+
}
136+
137+
return '@email/'.$this->theme.'/notification/body.txt.twig';
138+
}
139+
140+
public function getHtmlTemplate(): ?string
141+
{
142+
if ($template = parent::getHtmlTemplate()) {
143+
return $template;
144+
}
145+
146+
return '@email/'.$this->theme.'/notification/body.html.twig';
147+
}
148+
149+
public function getContext(): array
150+
{
151+
return array_merge($this->context, parent::getContext());
152+
}
153+
154+
public function getPreparedHeaders(): Headers
155+
{
156+
$headers = parent::getPreparedHeaders();
157+
158+
$importance = $this->context['importance'] ?? IMPORTANCE_LOW;
159+
$this->priority($this->determinePriority($importance));
160+
$headers->setHeaderBody('Text', 'Subject', sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));
161+
162+
return $headers;
163+
}
164+
165+
private function determinePriority(string $importance): int
166+
{
167+
switch ($importance) {
168+
case self::IMPORTANCE_URGENT:
169+
return self::PRIORITY_HIGHEST;
170+
case self::IMPORTANCE_HIGH:
171+
return self::PRIORITY_HIGH;
172+
case self::IMPORTANCE_MEDIUM:
173+
return self::PRIORITY_NORMAL;
174+
case self::IMPORTANCE_LOW:
175+
default:
176+
return self::PRIORITY_LOW;
177+
}
178+
}
179+
180+
private function getExceptionAsString($exception): string
181+
{
182+
if (class_exists(FlattenException::class)) {
183+
$exception = $exception instanceof FlattenException ? $exception : FlattenException::createFromThrowable($exception);
184+
185+
return $exception->getAsString();
186+
}
187+
188+
$message = \get_class($exception);
189+
if ('' != $exception->getMessage()) {
190+
$message .= ': '.$exception->getMessage();
191+
}
192+
193+
$message .= ' in '.$exception->getFile().':'.$exception->getLine()."\n";
194+
$message .= "Stack trace:\n".$exception->getTraceAsString()."\n\n";
195+
196+
return rtrim($message);
197+
}
198+
199+
/**
200+
* @internal
201+
*/
202+
public function __serialize(): array
203+
{
204+
return [$this->context, parent::__serialize()];
205+
}
206+
207+
/**
208+
* @internal
209+
*/
210+
public function __unserialize(array $data): void
211+
{
212+
[$this->context, $parentData] = $data;
213+
214+
parent::__unserialize($parentData);
215+
}
216+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
zurb_2

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy