Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a838f9c

Browse filesBrowse files
committed
[Mailer] added support for the profiler
1 parent 37265de commit a838f9c
Copy full SHA for a838f9c

File tree

12 files changed

+433
-3
lines changed
Filter options

12 files changed

+433
-3
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,10 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $
553553
$loader->load('messenger_debug.xml');
554554
}
555555

556+
if (class_exists(Mailer::class)) {
557+
$loader->load('mailer_debug.xml');
558+
}
559+
556560
$container->setParameter('profiler_listener.only_exceptions', $config['only_exceptions']);
557561
$container->setParameter('profiler_listener.only_master_requests', $config['only_master_requests']);
558562

+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<service id="mailer.logger_message_listener" class="Symfony\Component\Mailer\EventListener\MessageLoggerListener">
9+
<tag name="kernel.event_subscriber"/>
10+
</service>
11+
12+
<service id="mailer.data_collector" class="Symfony\Component\Mailer\DataCollector\MessageDataCollector">
13+
<argument type="service" id="mailer.logger_message_listener" />
14+
<tag name="data_collector" template="@WebProfiler/Collector/mailer.html.twig" id="mailer" />
15+
</service>
16+
</services>
17+
</container>

‎src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
4.4.0
55
-----
66

7+
* added support for the Mailer component
78
* added button to clear the ajax request tab
89
* deprecated the `ExceptionController::templateExists()` method
910
* deprecated the `TemplateManager::templateExists()` method
+202Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
2+
3+
{% block toolbar %}
4+
{% set events = collector.events %}
5+
6+
{% if events.messageCount %}
7+
{% set icon %}
8+
{% include('@WebProfiler/Icon/mailer.svg') %}
9+
<span class="sf-toolbar-value">{{ events.messageCount }}</span>
10+
{% endset %}
11+
12+
{% set text %}
13+
<div class="sf-toolbar-info-piece">
14+
<b>Sent messages</b>
15+
<span class="sf-toolbar-status">{{ events.messageCount }}</span>
16+
</div>
17+
18+
{% for transport in events.transports %}
19+
<div class="sf-toolbar-info-piece">
20+
<b>{{ transport }}</b>
21+
<span class="sf-toolbar-status">{{ events.messageCount(transport) }}</span>
22+
</div>
23+
{% endfor %}
24+
{% endset %}
25+
26+
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': profiler_url }) }}
27+
{% endif %}
28+
{% endblock %}
29+
30+
{% block head %}
31+
{{ parent() }}
32+
<style type="text/css">
33+
/* utility classes */
34+
.m-t-0 { margin-top: 0 !important; }
35+
.m-t-10 { margin-top: 10px !important; }
36+
37+
/* basic grid */
38+
.row {
39+
display: flex;
40+
flex-wrap: wrap;
41+
margin-right: -15px;
42+
margin-left: -15px;
43+
}
44+
.col {
45+
flex-basis: 0;
46+
flex-grow: 1;
47+
max-width: 100%;
48+
position: relative;
49+
width: 100%;
50+
min-height: 1px;
51+
padding-right: 15px;
52+
padding-left: 15px;
53+
}
54+
.col-4 {
55+
flex: 0 0 33.333333%;
56+
max-width: 33.333333%;
57+
}
58+
59+
/* small tabs */
60+
.sf-tabs-sm .tab-navigation li {
61+
font-size: 14px;
62+
padding: .3em .5em;
63+
}
64+
</style>
65+
{% endblock %}
66+
67+
{% block menu %}
68+
{% set events = collector.events %}
69+
70+
<span class="label {{ events.messageCount ? '' : 'disabled' }}">
71+
<span class="icon">{{ include('@WebProfiler/Icon/mailer.svg') }}</span>
72+
73+
<strong>E-mails</strong>
74+
{% if events.messageCount > 0 %}
75+
<span class="count">
76+
<span>{{ events.messageCount }}</span>
77+
</span>
78+
{% endif %}
79+
</span>
80+
{% endblock %}
81+
82+
{% block panel %}
83+
{% set events = collector.events %}
84+
85+
<h2>Emails</h2>
86+
87+
{% if not events.messageCount %}
88+
<div class="empty">
89+
<p>No emails were sent.</p>
90+
</div>
91+
{% endif %}
92+
93+
<div class="metrics">
94+
{% for transport in events.transports %}
95+
<div class="metric">
96+
<span class="value">{{ events.messageCount(transport) }}</span>
97+
<span class="label">{{ events.messageCount(transport) == 1 ? 'message' : 'messages' }}</label>
98+
</div>
99+
{% endfor %}
100+
</div>
101+
102+
{% for transport in events.transports %}
103+
<h3>{{ transport }}</h3>
104+
105+
<div class="card-block">
106+
<div class="sf-tabs sf-tabs-sm">
107+
{% for event in events.events(transport) %}
108+
{% set message = event.message %}
109+
<div class="tab">
110+
<h3 class="tab-title">Email #{{ loop.index }}</h3>
111+
<div class="tab-content">
112+
<div class="card">
113+
{% if message.headers is not defined %}
114+
{# RawMessage instance #}
115+
<div class="card-block">
116+
<pre class="prewrap" style="max-height: 600px">{{ message.toString() }}</pre>
117+
</div>
118+
{% else %}
119+
{# Message instance #}
120+
<div class="card-block">
121+
<span class="label">Subject</span>
122+
<h2 class="m-t-10">{{ message.headers.get('subject').bodyAsString() ?? '(empty)' }}</h2>
123+
</div>
124+
125+
<div class="card-block">
126+
<div class="row">
127+
<div class="col col-4">
128+
<span class="label">From</span>
129+
<pre class="prewrap">{{ (message.headers.get('from').bodyAsString() ?? '(empty)')|replace({'From:': ''}) }}</pre>
130+
131+
<span class="label">To</span>
132+
<pre class="prewrap">{{ (message.headers.get('to').bodyAsString() ?? '(empty)')|replace({'To:': ''}) }}</pre>
133+
</div>
134+
<div class="col">
135+
<span class="label">Headers</span>
136+
<pre class="prewrap">{% for header in message.headers.all|filter(header => (header.name ?? '') not in ['Subject', 'From', 'To']) %}
137+
{{- header.toString }}
138+
{%~ endfor %}</pre>
139+
</div>
140+
</div>
141+
</div>
142+
143+
<div class="card-block">
144+
{% if message.htmlBody is defined %}
145+
{# Email instance #}
146+
<div class="sf-tabs sf-tabs-sm">
147+
<div class="tab">
148+
<h3 class="tab-title">HTML Content</h3>
149+
<div class="tab-content">
150+
<pre class="prewrap" style="max-height: 600px">
151+
{%- if message.htmlCharset() %}
152+
{{- message.htmlBody()|convert_encoding('UTF-8', message.htmlCharset()) }}
153+
{%- else %}
154+
{{- message.htmlBody() }}
155+
{%- endif -%}
156+
</pre>
157+
</div>
158+
</div>
159+
<div class="tab">
160+
<h3 class="tab-title">Text Content</h3>
161+
<div class="tab-content">
162+
<pre class="prewrap" style="max-height: 600px">
163+
{%- if message.textCharset() %}
164+
{{- message.textBody()|convert_encoding('UTF-8', message.textCharset()) }}
165+
{%- else %}
166+
{{- message.textBody() }}
167+
{%- endif -%}
168+
</pre>
169+
</div>
170+
</div>
171+
{% for attachment in message.attachments %}
172+
<div class="tab">
173+
<h3 class="tab-title">Attachment #{{ loop.index }}</h3>
174+
<div class="tab-content">
175+
<pre class="prewrap" style="max-height: 600px">{{ attachment.toString() }}</pre>
176+
</div>
177+
</div>
178+
{% endfor %}
179+
{% endif %}
180+
<div class="tab">
181+
<h3 class="tab-title">Parts Hierarchy</h3>
182+
<div class="tab-content">
183+
<pre class="prewrap" style="max-height: 600px">{{ message.body().asDebugString() }}</pre>
184+
</div>
185+
</div>
186+
<div class="tab">
187+
<h3 class="tab-title">Raw</h3>
188+
<div class="tab-content">
189+
<pre class="prewrap" style="max-height: 600px">{{ message.toString() }}</pre>
190+
</div>
191+
</div>
192+
</div>
193+
</div>
194+
{% endif %}
195+
</div>
196+
</div>
197+
</div>
198+
{% endfor %}
199+
</div>
200+
</div>
201+
{% endfor %}
202+
{% endblock %}
+1Lines changed: 1 addition & 0 deletions
Loading

‎src/Symfony/Component/Mailer/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mailer/CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ CHANGELOG
44
4.4.0
55
-----
66

7+
* Added `MessageLoggerListener` to allow collecting send emails
8+
* Added `MessageDataCollector`
79
* [BC BREAK] `TransportInterface` has a new `getName()` method
810
* [BC BREAK] Classes `AbstractApiTransport` and `AbstractHttpTransport` moved under `Transport` sub-namespace.
911
* [BC BREAK] Transports depend on `Symfony\Contracts\EventDispatcher\EventDispatcherInterface`
+60Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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\Component\Mailer\DataCollector;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
17+
use Symfony\Component\Mailer\EventListener\MessageLoggerListener;
18+
use Symfony\Component\Mailer\Event\MessageEvents;
19+
20+
/**
21+
* @author Fabien Potencier <fabien@symfony.com>
22+
*/
23+
class MessageDataCollector extends DataCollector
24+
{
25+
private $events;
26+
27+
public function __construct(MessageLoggerListener $logger)
28+
{
29+
$this->events = $logger->getEvents();
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function collect(Request $request, Response $response, \Exception $exception = null)
36+
{
37+
$this->data['events'] = $this->events;
38+
}
39+
40+
public function getEvents(): MessageEvents
41+
{
42+
return $this->data['events'];
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
*/
48+
public function reset()
49+
{
50+
$this->data = [];
51+
}
52+
53+
/**
54+
* {@inheritdoc}
55+
*/
56+
public function getName()
57+
{
58+
return 'mailer';
59+
}
60+
}

‎src/Symfony/Component/Mailer/Event/MessageEvent.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mailer/Event/MessageEvent.php
+16-2Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,23 @@
1616
use Symfony\Component\Mime\RawMessage;
1717

1818
/**
19-
* Allows the transformation of a Message.
19+
* Allows the transformation of a Message and the SMTP Envelope before the email is sent.
2020
*
2121
* @author Fabien Potencier <fabien@symfony.com>
2222
*/
2323
class MessageEvent extends Event
2424
{
2525
private $message;
2626
private $envelope;
27+
private $transportName;
28+
private $queued;
2729

28-
public function __construct(RawMessage $message, SmtpEnvelope $envelope)
30+
public function __construct(RawMessage $message, SmtpEnvelope $envelope, string $transportName, $queued = false)
2931
{
3032
$this->message = $message;
3133
$this->envelope = $envelope;
34+
$this->transportName = $transportName;
35+
$this->queued = $queued;
3236
}
3337

3438
public function getMessage(): RawMessage
@@ -50,4 +54,14 @@ public function setEnvelope(SmtpEnvelope $envelope): void
5054
{
5155
$this->envelope = $envelope;
5256
}
57+
58+
public function getTransportName(): string
59+
{
60+
return $this->transportName;
61+
}
62+
63+
public function isQueued(): bool
64+
{
65+
return $this->queued;
66+
}
5367
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.