Skip to content

Commit 4ba9695

Browse files
committed
feature #421 Notify post author about new comments by sending email (voronkovich, javiereguiluz)
This PR was merged into the master branch. Discussion ---------- Notify post author about new comments by sending email See #420 Commits ------- 7dc958c Change prefix for translation messages f918956 Use '_fragment' parameter 1e83a1d Final round of help notes improvements bbc4077 Improved more help notes a596761 Improved some help notes ec601b6 Minor reword in the help note f37e552 Minor tweaks in the translation strings 4125af9 Add note about event listener's method f3b258a Remove default value for sender property b4a97be Use event listener and custom event trigger 7b6ba9a Notify post author about new comments
2 parents 4d93cda + 7dc958c commit 4ba9695

File tree

10 files changed

+178
-20
lines changed

10 files changed

+178
-20
lines changed

app/AppKernel.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ public function registerBundles()
2222
new CodeExplorerBundle\CodeExplorerBundle(),
2323
new AppBundle\AppBundle(),
2424
new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(), // used for initial population of non-SQLite databases in production envs
25-
// uncomment the following line if your application sends emails
26-
// new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
25+
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
2726
];
2827

2928
// Some bundles are only used while developing the application or during

app/Resources/translations/messages.en.xlf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,15 @@
281281
<target>Post deleted successfully!</target>
282282
</trans-unit>
283283

284+
<trans-unit id="notification.comment_created">
285+
<source>notification.comment_created</source>
286+
<target>Your post received a comment!</target>
287+
</trans-unit>
288+
<trans-unit id="notification.comment_created.description">
289+
<source>notification.comment_created.description</source>
290+
<target><![CDATA[Your post "%title%" has received a new comment. You can read the comment by following <a href="%link%">this link</a>]]></target>
291+
</trans-unit>
292+
284293
<trans-unit id="help.app_description">
285294
<source>help.app_description</source>
286295
<target><![CDATA[This is a <strong>demo application</strong> built in the Symfony Framework to illustrate the recommended way of developing Symfony applications.]]></target>

app/Resources/views/blog/post_show.html.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
{% for comment in post.comments %}
3232
<div class="row post-comment">
33+
<a name="comment_{{ comment.id }}"></a>
3334
<h4 class="col-sm-3">
3435
<strong>{{ comment.authorEmail }}</strong> {{ 'post.commented_on'|trans }}
3536
{# it's not mandatory to set the timezone in localizeddate(). This is done to

app/config/config.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ doctrine:
8383
# stores options that change the application behavior and parameters.yml
8484
# stores options that change from one server to another
8585
#
86-
# swiftmailer:
87-
# transport: "%mailer_transport%"
88-
# host: "%mailer_host%"
89-
# username: "%mailer_user%"
90-
# password: "%mailer_password%"
91-
# spool: { type: memory }
86+
swiftmailer:
87+
transport: "%mailer_transport%"
88+
host: "%mailer_host%"
89+
username: "%mailer_user%"
90+
password: "%mailer_password%"
91+
spool: { type: memory }

app/config/config_dev.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ monolog:
2929
# type: chromephp
3030
# level: info
3131

32-
#swiftmailer:
33-
# delivery_address: me@example.com
32+
swiftmailer:
33+
disable_delivery: true

app/config/parameters.yml.dist

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,9 @@ parameters:
3131
# $ php bin/console doctrine:schema:create
3232
# $ php bin/console doctrine:fixtures:load
3333

34-
# Uncomment these parameters if your application sends emails:
35-
#
36-
# mailer_transport: smtp
37-
# mailer_host: 127.0.0.1
38-
# mailer_user: ~
39-
# mailer_password: ~
40-
#
4134
# If you don't use a real mail server, you can send emails via your Gmail account.
4235
# see http://symfony.com/doc/current/cookbook/email/gmail.html
36+
mailer_transport: smtp
37+
mailer_host: 127.0.0.1
38+
mailer_user: ~
39+
mailer_password: ~

app/config/services.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,17 @@ services:
3131
tags:
3232
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
3333

34-
# Event subscribers are similar to event listeners but they don't need to add
35-
# a separate tag for each listened event. Instead, the PHP class of the event
36-
# subscriber includes a method that returns the list of listened events.
34+
app.comment_notification:
35+
class: AppBundle\EventListener\CommentNotificationListener
36+
arguments: ['@mailer', '@router', '@translator', '%app.notifications.email_sender%']
37+
# The "method" attribute of this tag is optional and defaults to "on + camelCasedEventName"
38+
# If the event is "comment.created" the method executed by default is "onCommentCreated()".
39+
tags:
40+
- { name: kernel.event_listener, event: comment.created, method: onCommentCreated }
41+
42+
# Event subscribers are similar to event listeners but they don't need service tags.
43+
# Instead, the PHP class of the event subscriber includes a method that returns
44+
# the list of events listened by that class.
3745
# See http://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber
3846
app.console_subscriber:
3947
class: AppBundle\EventListener\ConsoleEventSubscriber

src/AppBundle/Controller/BlogController.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313

1414
use AppBundle\Entity\Comment;
1515
use AppBundle\Entity\Post;
16+
use AppBundle\Events;
1617
use AppBundle\Form\CommentType;
1718
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
1819
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
1920
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
2021
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
2122
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
2223
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
24+
use Symfony\Component\EventDispatcher\GenericEvent;
2325
use Symfony\Component\HttpFoundation\Request;
2426
use Symfony\Component\HttpFoundation\Response;
2527

@@ -104,6 +106,20 @@ public function commentNewAction(Request $request, Post $post)
104106
$entityManager->persist($comment);
105107
$entityManager->flush();
106108

109+
// When triggering an event, you can optionally pass some information.
110+
// For simple applications, use the GenericEvent object provided by Symfony
111+
// to pass some PHP variables. For more complex applications, define your
112+
// own event object classes.
113+
// See http://symfony.com/doc/current/components/event_dispatcher/generic_event.html
114+
$event = new GenericEvent($comment);
115+
116+
// When an event is dispatched, Symfony notifies it to all the listeners
117+
// and subscribers registered to it. Listeners can modify the information
118+
// passed in the event and they can even modify the execution flow, so
119+
// there's no guarantee that the rest of this controller will be executed.
120+
// See http://symfony.com/doc/current/components/event_dispatcher.html
121+
$this->get('event_dispatcher')->dispatch(Events::COMMENT_CREATED, $event);
122+
107123
return $this->redirectToRoute('blog_post', ['slug' => $post->getSlug()]);
108124
}
109125

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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 AppBundle\EventListener;
13+
14+
use Symfony\Component\EventDispatcher\GenericEvent;
15+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16+
use Symfony\Component\Translation\TranslatorInterface;
17+
18+
/**
19+
* Notifies post's author about new comments.
20+
*
21+
* @author Oleg Voronkovich <oleg-voronkovich@yandex.ru>
22+
*/
23+
class CommentNotificationListener
24+
{
25+
/**
26+
* @var \Swift_Mailer
27+
*/
28+
private $mailer;
29+
30+
/**
31+
* @var TranslatorInterface
32+
*/
33+
private $translator;
34+
35+
/**
36+
* @var UrlGeneratorInterface
37+
*/
38+
private $urlGenerator;
39+
40+
/**
41+
* @var string
42+
*/
43+
private $sender;
44+
45+
/**
46+
* Constructor.
47+
*
48+
* @param \Swift_Mailer $mailer
49+
* @param UrlGeneratorInterface $urlGenerator
50+
* @param TranslatorInterface $translator
51+
* @param string $sender
52+
*/
53+
public function __construct(\Swift_Mailer $mailer, UrlGeneratorInterface $urlGenerator, TranslatorInterface $translator, $sender)
54+
{
55+
$this->mailer = $mailer;
56+
$this->urlGenerator = $urlGenerator;
57+
$this->translator = $translator;
58+
$this->sender = $sender;
59+
}
60+
61+
/**
62+
* @param GenericEvent $event
63+
*/
64+
public function onCommentCreated(GenericEvent $event)
65+
{
66+
$comment = $event->getSubject();
67+
$post = $comment->getPost();
68+
69+
$linkToPost = $this->urlGenerator->generate('blog_post', [
70+
'slug' => $post->getSlug(),
71+
'_fragment' => 'comment_'.$comment->getId(),
72+
], UrlGeneratorInterface::ABSOLUTE_URL);
73+
74+
$subject = $this->translator->trans('notification.comment_created');
75+
$body = $this->translator->trans('notification.comment_created.description', [
76+
'%title%' => $post->getTitle(),
77+
'%link%' => $linkToPost,
78+
]);
79+
80+
// Symfony uses a library called SwiftMailer to send emails. That's why
81+
// email messages are created instantiating a Swift_Message class.
82+
// See http://symfony.com/doc/current/email.html#sending-emails
83+
$message = \Swift_Message::newInstance()
84+
->setSubject($subject)
85+
->setTo($post->getAuthorEmail())
86+
->setFrom($this->sender)
87+
->setBody($body, 'text/html')
88+
;
89+
90+
// In app/config/config_dev.yml the 'disable_delivery' option is set to 'true'.
91+
// That's why in the development environment you won't actually receive any email.
92+
// However, you can inspect the contents of those unsent emails using the debug toolbar.
93+
// See http://symfony.com/doc/current/email/dev_environment.html#viewing-from-the-web-debug-toolbar
94+
$this->mailer->send($message);
95+
}
96+
}

src/AppBundle/Events.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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 AppBundle;
13+
14+
/**
15+
* This class defines the names of all the events dispatched in
16+
* the Symfony Demo application. It's not mandatory to create a
17+
* class like this, but it's considered a good practice.
18+
*
19+
* @author Oleg Voronkovich <oleg-voronkovich@yandex.ru>
20+
*/
21+
final class Events
22+
{
23+
/**
24+
* For the event naming conventions, see:
25+
* http://symfony.com/doc/current/components/event_dispatcher.html#naming-conventions.
26+
*
27+
* @Event("Symfony\Component\EventDispatcher\GenericEvent")
28+
*
29+
* @var string
30+
*/
31+
const COMMENT_CREATED = 'comment.created';
32+
}

0 commit comments

Comments
 (0)