diff --git a/app/AppKernel.php b/app/AppKernel.php
index 077c5db61..1129c08d5 100644
--- a/app/AppKernel.php
+++ b/app/AppKernel.php
@@ -22,8 +22,7 @@ public function registerBundles()
new CodeExplorerBundle\CodeExplorerBundle(),
new AppBundle\AppBundle(),
new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(), // used for initial population of non-SQLite databases in production envs
- // uncomment the following line if your application sends emails
- // new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
+ new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
];
// Some bundles are only used while developing the application or during
diff --git a/app/Resources/translations/messages.en.xlf b/app/Resources/translations/messages.en.xlf
index a41d20d13..b01531891 100644
--- a/app/Resources/translations/messages.en.xlf
+++ b/app/Resources/translations/messages.en.xlf
@@ -277,6 +277,15 @@
Post deleted successfully!
+
+ notification.comment_created
+ Your post received a comment!
+
+
+ notification.comment_created.description
+ this link]]>
+
+
help.app_descriptiondemo application built in the Symfony Framework to illustrate the recommended way of developing Symfony applications.]]>
diff --git a/app/Resources/views/blog/post_show.html.twig b/app/Resources/views/blog/post_show.html.twig
index c574ad115..09a1c3ee5 100644
--- a/app/Resources/views/blog/post_show.html.twig
+++ b/app/Resources/views/blog/post_show.html.twig
@@ -30,6 +30,7 @@
{% for comment in post.comments %}
+
{{ comment.authorEmail }} {{ 'post.commented_on'|trans }}
{# it's not mandatory to set the timezone in localizeddate(). This is done to
diff --git a/app/config/config.yml b/app/config/config.yml
index 71d345a78..2ee3b9ccc 100644
--- a/app/config/config.yml
+++ b/app/config/config.yml
@@ -83,9 +83,9 @@ doctrine:
# stores options that change the application behavior and parameters.yml
# stores options that change from one server to another
#
-# swiftmailer:
-# transport: "%mailer_transport%"
-# host: "%mailer_host%"
-# username: "%mailer_user%"
-# password: "%mailer_password%"
-# spool: { type: memory }
+swiftmailer:
+ transport: "%mailer_transport%"
+ host: "%mailer_host%"
+ username: "%mailer_user%"
+ password: "%mailer_password%"
+ spool: { type: memory }
diff --git a/app/config/config_dev.yml b/app/config/config_dev.yml
index ff9c5dfef..b26cb19b9 100644
--- a/app/config/config_dev.yml
+++ b/app/config/config_dev.yml
@@ -29,5 +29,5 @@ monolog:
# type: chromephp
# level: info
-#swiftmailer:
-# delivery_address: me@example.com
+swiftmailer:
+ disable_delivery: true
diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist
index 4cc6ec1e3..a50013b68 100644
--- a/app/config/parameters.yml.dist
+++ b/app/config/parameters.yml.dist
@@ -31,12 +31,9 @@ parameters:
# $ php bin/console doctrine:schema:create
# $ php bin/console doctrine:fixtures:load
- # Uncomment these parameters if your application sends emails:
- #
- # mailer_transport: smtp
- # mailer_host: 127.0.0.1
- # mailer_user: ~
- # mailer_password: ~
- #
# If you don't use a real mail server, you can send emails via your Gmail account.
# see http://symfony.com/doc/current/cookbook/email/gmail.html
+ mailer_transport: smtp
+ mailer_host: 127.0.0.1
+ mailer_user: ~
+ mailer_password: ~
diff --git a/app/config/services.yml b/app/config/services.yml
index bfe5ee2f7..a3c388a99 100644
--- a/app/config/services.yml
+++ b/app/config/services.yml
@@ -31,9 +31,17 @@ services:
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
- # Event subscribers are similar to event listeners but they don't need to add
- # a separate tag for each listened event. Instead, the PHP class of the event
- # subscriber includes a method that returns the list of listened events.
+ app.comment_notification:
+ class: AppBundle\EventListener\CommentNotificationListener
+ arguments: ['@mailer', '@router', '@translator', '%app.notifications.email_sender%']
+ # The "method" attribute of this tag is optional and defaults to "on + camelCasedEventName"
+ # If the event is "comment.created" the method executed by default is "onCommentCreated()".
+ tags:
+ - { name: kernel.event_listener, event: comment.created, method: onCommentCreated }
+
+ # Event subscribers are similar to event listeners but they don't need service tags.
+ # Instead, the PHP class of the event subscriber includes a method that returns
+ # the list of events listened by that class.
# See http://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber
app.console_subscriber:
class: AppBundle\EventListener\ConsoleEventSubscriber
diff --git a/src/AppBundle/Controller/BlogController.php b/src/AppBundle/Controller/BlogController.php
index 3c107b29d..039ce867f 100644
--- a/src/AppBundle/Controller/BlogController.php
+++ b/src/AppBundle/Controller/BlogController.php
@@ -13,6 +13,7 @@
use AppBundle\Entity\Comment;
use AppBundle\Entity\Post;
+use AppBundle\Events;
use AppBundle\Form\CommentType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
@@ -20,6 +21,7 @@
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Symfony\Component\EventDispatcher\GenericEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -96,6 +98,20 @@ public function commentNewAction(Request $request, Post $post)
$entityManager->persist($comment);
$entityManager->flush();
+ // When triggering an event, you can optionally pass some information.
+ // For simple applications, use the GenericEvent object provided by Symfony
+ // to pass some PHP variables. For more complex applications, define your
+ // own event object classes.
+ // See http://symfony.com/doc/current/components/event_dispatcher/generic_event.html
+ $event = new GenericEvent($comment);
+
+ // When an event is dispatched, Symfony notifies it to all the listeners
+ // and subscribers registered to it. Listeners can modify the information
+ // passed in the event and they can even modify the execution flow, so
+ // there's no guarantee that the rest of this controller will be executed.
+ // See http://symfony.com/doc/current/components/event_dispatcher.html
+ $this->get('event_dispatcher')->dispatch(Events::COMMENT_CREATED, $event);
+
return $this->redirectToRoute('blog_post', ['slug' => $post->getSlug()]);
}
diff --git a/src/AppBundle/EventListener/CommentNotificationListener.php b/src/AppBundle/EventListener/CommentNotificationListener.php
new file mode 100644
index 000000000..ff28cae0a
--- /dev/null
+++ b/src/AppBundle/EventListener/CommentNotificationListener.php
@@ -0,0 +1,96 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace AppBundle\EventListener;
+
+use Symfony\Component\EventDispatcher\GenericEvent;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Translation\TranslatorInterface;
+
+/**
+ * Notifies post's author about new comments.
+ *
+ * @author Oleg Voronkovich
+ */
+class CommentNotificationListener
+{
+ /**
+ * @var \Swift_Mailer
+ */
+ private $mailer;
+
+ /**
+ * @var TranslatorInterface
+ */
+ private $translator;
+
+ /**
+ * @var UrlGeneratorInterface
+ */
+ private $urlGenerator;
+
+ /**
+ * @var string
+ */
+ private $sender;
+
+ /**
+ * Constructor.
+ *
+ * @param \Swift_Mailer $mailer
+ * @param UrlGeneratorInterface $urlGenerator
+ * @param TranslatorInterface $translator
+ * @param string $sender
+ */
+ public function __construct(\Swift_Mailer $mailer, UrlGeneratorInterface $urlGenerator, TranslatorInterface $translator, $sender)
+ {
+ $this->mailer = $mailer;
+ $this->urlGenerator = $urlGenerator;
+ $this->translator = $translator;
+ $this->sender = $sender;
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onCommentCreated(GenericEvent $event)
+ {
+ $comment = $event->getSubject();
+ $post = $comment->getPost();
+
+ $linkToPost = $this->urlGenerator->generate('blog_post', [
+ 'slug' => $post->getSlug(),
+ '_fragment' => 'comment_'.$comment->getId(),
+ ], UrlGeneratorInterface::ABSOLUTE_URL);
+
+ $subject = $this->translator->trans('notification.comment_created');
+ $body = $this->translator->trans('notification.comment_created.description', [
+ '%title%' => $post->getTitle(),
+ '%link%' => $linkToPost,
+ ]);
+
+ // Symfony uses a library called SwiftMailer to send emails. That's why
+ // email messages are created instantiating a Swift_Message class.
+ // See http://symfony.com/doc/current/email.html#sending-emails
+ $message = \Swift_Message::newInstance()
+ ->setSubject($subject)
+ ->setTo($post->getAuthorEmail())
+ ->setFrom($this->sender)
+ ->setBody($body, 'text/html')
+ ;
+
+ // In app/config/config_dev.yml the 'disable_delivery' option is set to 'true'.
+ // That's why in the development environment you won't actually receive any email.
+ // However, you can inspect the contents of those unsent emails using the debug toolbar.
+ // See http://symfony.com/doc/current/email/dev_environment.html#viewing-from-the-web-debug-toolbar
+ $this->mailer->send($message);
+ }
+}
diff --git a/src/AppBundle/Events.php b/src/AppBundle/Events.php
new file mode 100644
index 000000000..cc504a092
--- /dev/null
+++ b/src/AppBundle/Events.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace AppBundle;
+
+/**
+ * This class defines the names of all the events dispatched in
+ * the Symfony Demo application. It's not mandatory to create a
+ * class like this, but it's considered a good practice.
+ *
+ * @author Oleg Voronkovich
+ */
+final class Events
+{
+ /**
+ * For the event naming conventions, see:
+ * http://symfony.com/doc/current/components/event_dispatcher.html#naming-conventions.
+ *
+ * @Event("Symfony\Component\EventDispatcher\GenericEvent")
+ *
+ * @var string
+ */
+ const COMMENT_CREATED = 'comment.created';
+}
{{ comment.authorEmail }} {{ 'post.commented_on'|trans }} {# it's not mandatory to set the timezone in localizeddate(). This is done to diff --git a/app/config/config.yml b/app/config/config.yml index 71d345a78..2ee3b9ccc 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -83,9 +83,9 @@ doctrine: # stores options that change the application behavior and parameters.yml # stores options that change from one server to another # -# swiftmailer: -# transport: "%mailer_transport%" -# host: "%mailer_host%" -# username: "%mailer_user%" -# password: "%mailer_password%" -# spool: { type: memory } +swiftmailer: + transport: "%mailer_transport%" + host: "%mailer_host%" + username: "%mailer_user%" + password: "%mailer_password%" + spool: { type: memory } diff --git a/app/config/config_dev.yml b/app/config/config_dev.yml index ff9c5dfef..b26cb19b9 100644 --- a/app/config/config_dev.yml +++ b/app/config/config_dev.yml @@ -29,5 +29,5 @@ monolog: # type: chromephp # level: info -#swiftmailer: -# delivery_address: me@example.com +swiftmailer: + disable_delivery: true diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 4cc6ec1e3..a50013b68 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -31,12 +31,9 @@ parameters: # $ php bin/console doctrine:schema:create # $ php bin/console doctrine:fixtures:load - # Uncomment these parameters if your application sends emails: - # - # mailer_transport: smtp - # mailer_host: 127.0.0.1 - # mailer_user: ~ - # mailer_password: ~ - # # If you don't use a real mail server, you can send emails via your Gmail account. # see http://symfony.com/doc/current/cookbook/email/gmail.html + mailer_transport: smtp + mailer_host: 127.0.0.1 + mailer_user: ~ + mailer_password: ~ diff --git a/app/config/services.yml b/app/config/services.yml index bfe5ee2f7..a3c388a99 100644 --- a/app/config/services.yml +++ b/app/config/services.yml @@ -31,9 +31,17 @@ services: tags: - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest } - # Event subscribers are similar to event listeners but they don't need to add - # a separate tag for each listened event. Instead, the PHP class of the event - # subscriber includes a method that returns the list of listened events. + app.comment_notification: + class: AppBundle\EventListener\CommentNotificationListener + arguments: ['@mailer', '@router', '@translator', '%app.notifications.email_sender%'] + # The "method" attribute of this tag is optional and defaults to "on + camelCasedEventName" + # If the event is "comment.created" the method executed by default is "onCommentCreated()". + tags: + - { name: kernel.event_listener, event: comment.created, method: onCommentCreated } + + # Event subscribers are similar to event listeners but they don't need service tags. + # Instead, the PHP class of the event subscriber includes a method that returns + # the list of events listened by that class. # See http://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber app.console_subscriber: class: AppBundle\EventListener\ConsoleEventSubscriber diff --git a/src/AppBundle/Controller/BlogController.php b/src/AppBundle/Controller/BlogController.php index 3c107b29d..039ce867f 100644 --- a/src/AppBundle/Controller/BlogController.php +++ b/src/AppBundle/Controller/BlogController.php @@ -13,6 +13,7 @@ use AppBundle\Entity\Comment; use AppBundle\Entity\Post; +use AppBundle\Events; use AppBundle\Form\CommentType; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; @@ -20,6 +21,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\EventDispatcher\GenericEvent; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -96,6 +98,20 @@ public function commentNewAction(Request $request, Post $post) $entityManager->persist($comment); $entityManager->flush(); + // When triggering an event, you can optionally pass some information. + // For simple applications, use the GenericEvent object provided by Symfony + // to pass some PHP variables. For more complex applications, define your + // own event object classes. + // See http://symfony.com/doc/current/components/event_dispatcher/generic_event.html + $event = new GenericEvent($comment); + + // When an event is dispatched, Symfony notifies it to all the listeners + // and subscribers registered to it. Listeners can modify the information + // passed in the event and they can even modify the execution flow, so + // there's no guarantee that the rest of this controller will be executed. + // See http://symfony.com/doc/current/components/event_dispatcher.html + $this->get('event_dispatcher')->dispatch(Events::COMMENT_CREATED, $event); + return $this->redirectToRoute('blog_post', ['slug' => $post->getSlug()]); } diff --git a/src/AppBundle/EventListener/CommentNotificationListener.php b/src/AppBundle/EventListener/CommentNotificationListener.php new file mode 100644 index 000000000..ff28cae0a --- /dev/null +++ b/src/AppBundle/EventListener/CommentNotificationListener.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AppBundle\EventListener; + +use Symfony\Component\EventDispatcher\GenericEvent; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Translation\TranslatorInterface; + +/** + * Notifies post's author about new comments. + * + * @author Oleg Voronkovich
+ */
+class CommentNotificationListener
+{
+ /**
+ * @var \Swift_Mailer
+ */
+ private $mailer;
+
+ /**
+ * @var TranslatorInterface
+ */
+ private $translator;
+
+ /**
+ * @var UrlGeneratorInterface
+ */
+ private $urlGenerator;
+
+ /**
+ * @var string
+ */
+ private $sender;
+
+ /**
+ * Constructor.
+ *
+ * @param \Swift_Mailer $mailer
+ * @param UrlGeneratorInterface $urlGenerator
+ * @param TranslatorInterface $translator
+ * @param string $sender
+ */
+ public function __construct(\Swift_Mailer $mailer, UrlGeneratorInterface $urlGenerator, TranslatorInterface $translator, $sender)
+ {
+ $this->mailer = $mailer;
+ $this->urlGenerator = $urlGenerator;
+ $this->translator = $translator;
+ $this->sender = $sender;
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onCommentCreated(GenericEvent $event)
+ {
+ $comment = $event->getSubject();
+ $post = $comment->getPost();
+
+ $linkToPost = $this->urlGenerator->generate('blog_post', [
+ 'slug' => $post->getSlug(),
+ '_fragment' => 'comment_'.$comment->getId(),
+ ], UrlGeneratorInterface::ABSOLUTE_URL);
+
+ $subject = $this->translator->trans('notification.comment_created');
+ $body = $this->translator->trans('notification.comment_created.description', [
+ '%title%' => $post->getTitle(),
+ '%link%' => $linkToPost,
+ ]);
+
+ // Symfony uses a library called SwiftMailer to send emails. That's why
+ // email messages are created instantiating a Swift_Message class.
+ // See http://symfony.com/doc/current/email.html#sending-emails
+ $message = \Swift_Message::newInstance()
+ ->setSubject($subject)
+ ->setTo($post->getAuthorEmail())
+ ->setFrom($this->sender)
+ ->setBody($body, 'text/html')
+ ;
+
+ // In app/config/config_dev.yml the 'disable_delivery' option is set to 'true'.
+ // That's why in the development environment you won't actually receive any email.
+ // However, you can inspect the contents of those unsent emails using the debug toolbar.
+ // See http://symfony.com/doc/current/email/dev_environment.html#viewing-from-the-web-debug-toolbar
+ $this->mailer->send($message);
+ }
+}
diff --git a/src/AppBundle/Events.php b/src/AppBundle/Events.php
new file mode 100644
index 000000000..cc504a092
--- /dev/null
+++ b/src/AppBundle/Events.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace AppBundle;
+
+/**
+ * This class defines the names of all the events dispatched in
+ * the Symfony Demo application. It's not mandatory to create a
+ * class like this, but it's considered a good practice.
+ *
+ * @author Oleg Voronkovich
+ */
+final class Events
+{
+ /**
+ * For the event naming conventions, see:
+ * http://symfony.com/doc/current/components/event_dispatcher.html#naming-conventions.
+ *
+ * @Event("Symfony\Component\EventDispatcher\GenericEvent")
+ *
+ * @var string
+ */
+ const COMMENT_CREATED = 'comment.created';
+}