Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ba2a6ae

Browse files
committed
[Twig] Add NotificationEmail
1 parent 24faadc commit ba2a6ae

File tree

11 files changed

+2087
-3
lines changed

11 files changed

+2087
-3
lines changed

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: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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 <[email protected]>
23+
*/
24+
class NotificationEmail extends TemplatedEmail
25+
{
26+
public const URGENT = 'urgent';
27+
public const HIGH = 'high';
28+
public const MEDIUM = 'medium';
29+
public const LOW = 'low';
30+
31+
private const DEFAULT_HTML_TEMPLATE_PATH = '@email/notification.html.twig';
32+
private const DEFAULT_TEXT_TEMPLATE_PATH = '@email/notification.txt.twig';
33+
34+
private static $htmlTemplatePath = self::DEFAULT_HTML_TEMPLATE_PATH;
35+
private static $textTemplatePath = self::DEFAULT_TEXT_TEMPLATE_PATH;
36+
37+
private $context = [
38+
'importance' => self::LOW,
39+
'content' => '',
40+
'exception' => false,
41+
'action_text' => null,
42+
'action_url' => null,
43+
'markdown' => false,
44+
'raw' => false,
45+
];
46+
47+
public function __construct(Headers $headers = null, AbstractPart $body = null)
48+
{
49+
if (!class_exists(CssInlinerExtension::class)) {
50+
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));
51+
}
52+
53+
if (!class_exists(InkyExtension::class)) {
54+
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));
55+
}
56+
57+
parent::__construct($headers, $body);
58+
}
59+
60+
/**
61+
* @return $this
62+
*/
63+
public function markdown()
64+
{
65+
if (!class_exists(MarkdownExtension::class)) {
66+
throw new \LogicException(sprintf('You cannot use "%s" if the Markdown Twig extension is not available; try running "composer require twig/markdown-extra".', __METHOD__));
67+
}
68+
69+
$this->context['markdown'] = true;
70+
71+
return $this;
72+
}
73+
74+
/**
75+
* @return $this
76+
*/
77+
public function content(string $content, bool $raw = false)
78+
{
79+
$this->context['content'] = $content;
80+
$this->context['raw'] = $raw;
81+
82+
return $this;
83+
}
84+
85+
/**
86+
* @return $this
87+
*/
88+
public function action(string $text, string $url)
89+
{
90+
$this->context['action_text'] = $text;
91+
$this->context['action_url'] = $url;
92+
93+
return $this;
94+
}
95+
96+
/**
97+
* @return self
98+
*/
99+
public function importance(string $importance)
100+
{
101+
$this->context['importance'] = $importance;
102+
103+
return $this;
104+
}
105+
106+
/**
107+
* @param \Throwable|FlattenException
108+
*
109+
* @return $this
110+
*/
111+
public function exception($exception)
112+
{
113+
$exceptionAsString = $this->getExceptionAsString($exception);
114+
115+
$this->context['exception'] = true;
116+
$this->attach($exceptionAsString, 'exception.txt', 'text/plain');
117+
$this->importance(self::URGENT);
118+
119+
if (!$this->getSubject()) {
120+
$this->subject($exception->getMessage());
121+
}
122+
123+
return $this;
124+
}
125+
126+
public static function setDefaultTemplates(?string $htmlTemplatePath = null, ?string $textTemplatePath = null)
127+
{
128+
self::$htmlTemplatePath = $htmlTemplatePath ?: self::DEFAULT_HTML_TEMPLATE_PATH;
129+
self::$textTemplatePath = $textTemplatePath ?: self::DEFAULT_TEXT_TEMPLATE_PATH;
130+
}
131+
132+
public function getTextTemplate(): ?string
133+
{
134+
if ($template = parent::getTextTemplate()) {
135+
return $template;
136+
}
137+
138+
return self::$textTemplatePath;
139+
}
140+
141+
public function getHtmlTemplate(): ?string
142+
{
143+
if ($template = parent::getHtmlTemplate()) {
144+
return $template;
145+
}
146+
147+
return self::$htmlTemplatePath;
148+
}
149+
150+
public function getContext(): array
151+
{
152+
return array_merge($this->context, parent::getContext());
153+
}
154+
155+
public function getPreparedHeaders(): Headers
156+
{
157+
$headers = parent::getPreparedHeaders();
158+
159+
$importance = $this->context['importance'] ?? self::LOW;
160+
$this->priority($this->determinePriority($importance));
161+
$headers->setHeaderBody('Text', 'Subject', sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));
162+
163+
return $headers;
164+
}
165+
166+
private function determinePriority(string $importance): int
167+
{
168+
switch ($importance) {
169+
case self::URGENT:
170+
return self::PRIORITY_HIGHEST;
171+
case self::HIGH:
172+
return self::PRIORITY_HIGH;
173+
case self::MEDIUM:
174+
return self::PRIORITY_NORMAL;
175+
case self::LOW:
176+
return self::PRIORITY_LOW;
177+
default:
178+
return self::PRIORITY_LOWEST;
179+
}
180+
}
181+
182+
private function getExceptionAsString($exception): string
183+
{
184+
if (class_exists(FlattenException::class)) {
185+
$exception = $exception instanceof FlattenException ? $exception : FlattenException::createFromThrowable($exception);
186+
187+
return $exception->getAsString();
188+
}
189+
190+
$message = \get_class($exception);
191+
if ('' != $exception->getMessage()) {
192+
$message .= ': '.$exception->getMessage();
193+
}
194+
195+
$message .= ' in '.$exception->getFile().':'.$exception->getLine()."\n";
196+
$message .= "Stack trace:\n".$exception->getTraceAsString()."\n\n";
197+
198+
return rtrim($message);
199+
}
200+
201+
/**
202+
* @internal
203+
*/
204+
public function __serialize(): array
205+
{
206+
return [$this->context, parent::__serialize()];
207+
}
208+
209+
/**
210+
* @internal
211+
*/
212+
public function __unserialize(array $data): void
213+
{
214+
[$this->context, $parentData] = $data;
215+
216+
parent::__unserialize($parentData);
217+
}
218+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
body {
2+
background: #f3f3f3;
3+
}
4+
5+
.wrapper.secondary {
6+
background: #f3f3f3;
7+
}
8+
9+
.container.body_alert {
10+
border-top: 8px solid #ec5840;
11+
}
12+
13+
.container.body_warning {
14+
border-top: 8px solid #ffae00;
15+
}
16+
17+
.container.body_default {
18+
border-top: 8px solid #aaaaaa;
19+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{% filter inky_to_html|inline_css %}
2+
<html>
3+
<head>
4+
<style>
5+
{% block style %}
6+
{{ source("@email/zurb.css") }}
7+
{{ source("@email/notification.css") }}
8+
{% endblock %}
9+
</style>
10+
</head>
11+
<body>
12+
<spacer size="32"></spacer>
13+
<container class="body_{{ ("urgent" == importance ? "alert" : ("high" == importance ? "warning" : "default")) }}">
14+
<spacer size="16"></spacer>
15+
<row>
16+
<columns large="12" small="12">
17+
{% block lead %}
18+
<small><strong>{{ importance|upper }}</strong></small>
19+
<p class="lead">
20+
{{ email.subject }}
21+
</p>
22+
{% endblock %}
23+
24+
{% block content %}
25+
{% if markdown %}
26+
{{ include('@email/notification_body_markdown.html.twig') }}
27+
{% else %}
28+
{{ (raw ? content|raw : content)|nl2br }}
29+
{% endif %}
30+
{% endblock %}
31+
32+
{% block action %}
33+
{% if action_url %}
34+
<spacer size="16"></spacer>
35+
<button href="{{ action_url }}">{{ action_text }}</button>
36+
{% endif %}
37+
{% endblock %}
38+
39+
{% block exception %}
40+
{% if exception %}
41+
<spacer size="16"></spacer>
42+
<p><em>Exception stack trace attached.</em></p>
43+
{% endif %}
44+
{% endblock %}
45+
</columns>
46+
</row>
47+
48+
<wrapper class="secondary">
49+
<spacer size="16"></spacer>
50+
{% block footer %}
51+
<row>
52+
<columns small="12" large="6">
53+
{% block footer_content %}
54+
<p><small>Notification e-mail sent by Symfony</small></p>
55+
{% endblock %}
56+
</columns>
57+
</row>
58+
{% endblock %}
59+
</wrapper>
60+
</container>
61+
</body>
62+
</html>
63+
{% endfilter %}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{% block lead %}
2+
{{ email.subject }}
3+
{% endblock %}
4+
5+
{% block content %}
6+
{{ content }}
7+
{% endblock %}
8+
9+
{% block action %}
10+
{% if action_url %}
11+
{{ action_url }}: {{ action_text }}
12+
{% endif %}
13+
{% endblock %}
14+
15+
{% block exception %}
16+
{% if exception %}
17+
Exception stack trace attached.
18+
{{ exception }}
19+
{% endif %}
20+
{% endblock %}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{% filter markdown_to_html %}
2+
{{ raw ? content|raw : content }}
3+
{% endfilter %}

0 commit comments

Comments
 (0)