Skip to content

Commit b97af7e

Browse files
committed
[Twig] Add NotificationEmail
1 parent e6eadae commit b97af7e

File tree

15 files changed

+2121
-14
lines changed

15 files changed

+2121
-14
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: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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 const DEFAULT_THEME = '@email/zurb_2/notification';
32+
33+
private static $defaultTheme = self::DEFAULT_THEME;
34+
35+
private $theme;
36+
private $context = [
37+
'importance' => self::IMPORTANCE_LOW,
38+
'content' => '',
39+
'exception' => false,
40+
'action_text' => null,
41+
'action_url' => null,
42+
'markdown' => false,
43+
'raw' => false,
44+
];
45+
46+
public function __construct(Headers $headers = null, AbstractPart $body = null)
47+
{
48+
if (!class_exists(CssInlinerExtension::class)) {
49+
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));
50+
}
51+
52+
if (!class_exists(InkyExtension::class)) {
53+
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));
54+
}
55+
56+
parent::__construct($headers, $body);
57+
}
58+
59+
/**
60+
* @return $this
61+
*/
62+
public function markdown()
63+
{
64+
if (!class_exists(MarkdownExtension::class)) {
65+
throw new \LogicException(sprintf('You cannot use "%s" if the Markdown Twig extension is not available; try running "composer require twig/markdown-extra".', __METHOD__));
66+
}
67+
68+
$this->context['markdown'] = true;
69+
70+
return $this;
71+
}
72+
73+
/**
74+
* @return $this
75+
*/
76+
public function content(string $content, bool $raw = false)
77+
{
78+
$this->context['content'] = $content;
79+
$this->context['raw'] = $raw;
80+
81+
return $this;
82+
}
83+
84+
/**
85+
* @return $this
86+
*/
87+
public function action(string $text, string $url)
88+
{
89+
$this->context['action_text'] = $text;
90+
$this->context['action_url'] = $url;
91+
92+
return $this;
93+
}
94+
95+
/**
96+
* @return self
97+
*/
98+
public function importance(string $importance)
99+
{
100+
$this->context['importance'] = $importance;
101+
102+
return $this;
103+
}
104+
105+
/**
106+
* @param \Throwable|FlattenException
107+
*
108+
* @return $this
109+
*/
110+
public function exception($exception)
111+
{
112+
$exceptionAsString = $this->getExceptionAsString($exception);
113+
114+
$this->context['exception'] = true;
115+
$this->attach($exceptionAsString, 'exception.txt', 'text/plain');
116+
$this->importance(self::IMPORTANCE_URGENT);
117+
118+
if (!$this->getSubject()) {
119+
$this->subject($exception->getMessage());
120+
}
121+
122+
return $this;
123+
}
124+
125+
/**
126+
* @return $this
127+
*/
128+
public function theme(string $themePath = null)
129+
{
130+
$this->theme = $themePath;
131+
132+
return $this;
133+
}
134+
135+
public static function setDefaultTheme(string $themePath = null)
136+
{
137+
self::$defaultTheme = $themePath ?: self::DEFAULT_THEME;
138+
}
139+
140+
public function getTextTemplate(): ?string
141+
{
142+
if ($template = parent::getTextTemplate()) {
143+
return $template;
144+
}
145+
146+
return ($this->theme ?: self::$defaultTheme).'.txt.twig';
147+
}
148+
149+
public function getHtmlTemplate(): ?string
150+
{
151+
if ($template = parent::getHtmlTemplate()) {
152+
return $template;
153+
}
154+
155+
return ($this->theme ?: self::$defaultTheme).'.html.twig';
156+
}
157+
158+
public function getContext(): array
159+
{
160+
return array_merge($this->context, parent::getContext());
161+
}
162+
163+
public function getPreparedHeaders(): Headers
164+
{
165+
$headers = parent::getPreparedHeaders();
166+
167+
$importance = $this->context['importance'] ?? IMPORTANCE_LOW;
168+
$this->priority($this->determinePriority($importance));
169+
$headers->setHeaderBody('Text', 'Subject', sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));
170+
171+
return $headers;
172+
}
173+
174+
private function determinePriority(string $importance): int
175+
{
176+
switch ($importance) {
177+
case self::IMPORTANCE_URGENT:
178+
return self::PRIORITY_HIGHEST;
179+
case self::IMPORTANCE_HIGH:
180+
return self::PRIORITY_HIGH;
181+
case self::IMPORTANCE_MEDIUM:
182+
return self::PRIORITY_NORMAL;
183+
case self::IMPORTANCE_LOW:
184+
return self::PRIORITY_LOW;
185+
default:
186+
return self::PRIORITY_LOWEST;
187+
}
188+
}
189+
190+
private function getExceptionAsString($exception): string
191+
{
192+
if (class_exists(FlattenException::class)) {
193+
$exception = $exception instanceof FlattenException ? $exception : FlattenException::createFromThrowable($exception);
194+
195+
return $exception->getAsString();
196+
}
197+
198+
$message = \get_class($exception);
199+
if ('' != $exception->getMessage()) {
200+
$message .= ': '.$exception->getMessage();
201+
}
202+
203+
$message .= ' in '.$exception->getFile().':'.$exception->getLine()."\n";
204+
$message .= "Stack trace:\n".$exception->getTraceAsString()."\n\n";
205+
206+
return rtrim($message);
207+
}
208+
209+
/**
210+
* @internal
211+
*/
212+
public function __serialize(): array
213+
{
214+
return [$this->context, parent::__serialize()];
215+
}
216+
217+
/**
218+
* @internal
219+
*/
220+
public function __unserialize(array $data): void
221+
{
222+
[$this->context, $parentData] = $data;
223+
224+
parent::__unserialize($parentData);
225+
}
226+
}

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