phpsymfonyloggingswiftmailersymfony2

Logging swiftmailer send() activity in symfony2


Im using swiftmailer for sending mails from my symfony2.2 project. Is there a way to log globally all email info and send results?

It would be great if mailer send() method have trigger somę event, but I can't see it does.


Solution

  • I did it this way:

    1. My service configuration

    # /src/Tiriana/MyBundle/Resources/config/services.yml
    parameters:
         swiftmailer.class:  Tiriana\MyBundle\Util\MailerWrapper
    

    2. Mailer wraper service

    It extends Swift_Mailer, because it is passed to different classes expecting mailer to be instance of Swift_Mailer. And it creates Swift_Mailer instance as a field, because... $transport is private in \Swith_Mailer (link). Code would be so much better if $transport was protected...

    // /src/Tiriana/MyBundle/Util/MailerWrapper.php
    namespace Tiriana\MyBundle\Util;
    
    use Monolog\Logger;
    use Monolog\Handler\StreamHandler;
    
    class MailerWrapper extends \Swift_Mailer
    {
        private $_logger;
    
        /** @var \Swift_Mailer */
        private $_mailer;
    
        public function send(\Swift_Mime_Message $message, &$failedRecipients = null)
        {
            $this->_log('BEFORE SEND');  // <-- add your logic here
            $ret = $this->_mailer->send($message, $failedRecipients);
            $this->_log('AFTER SEND');  // <-- add your logic here
    
            return $ret;
        }
    
        /** @return Logger */
        public function getLogger()
        {
            return $this->_logger;
        }
    
        protected function _log($msg)
        {
            $this->getLogger()->debug(__CLASS__ . ": " . $msg);
        }
    
        public function __construct(\Swift_Transport $transport, Logger $logger)
        {
            /* we need _mailer because _transport is private
               (not protected) in Swift_Mailer, unfortunately... */
            $this->_mailer = parent::newInstance($transport);
            $this->_logger = $logger;
        }
    
        public static function newInstance(\Swift_Transport $transport)
        {
            return new self($transport);
        }
    
        public function getTransport()
        {
            return $this->_mailer->getTransport();
        }
    
        public function registerPlugin(Swift_Events_EventListener $plugin)
        {
            $this->getTransport()->registerPlugin($plugin);
        }
    }
    

    3. Bundle builder

    // /src/Tiriana/MyBundle/TirianaMyBundle.php
    namespace Tiriana\MyBundle;
    
    use Symfony\Component\HttpKernel\Bundle\Bundle;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    
    use Tiriana\MyBundle\DependencyInjection\Compiler\OverrideServiceSwiftMailer;
    
    class TirianaMyBundle extends Bundle
    {
        public function build(ContainerBuilder $container)
        {
            parent::build($container);
            $container->addCompilerPass(new OverrideServiceSwiftMailer());  // <-- ADD THIS LINE
        }
    }
    

    4. And OverrideServiceSwiftMailer class

    // /src/Tiriana/MyBundle/DependencyInjection/Compiler/OverrideServiceSwiftMailer.php
    namespace Tiriana\MyBundle\DependencyInjection\Compiler;
    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\DependencyInjection\Reference;
    
    class OverrideServiceSwiftMailer implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            /* @var $definition \Symfony\Component\DependencyInjection\DefinitionDecorator */
            $definition = $container->findDefinition('mailer');
            $definition->addArgument(new Reference('logger'));
            /* add more dependencies if you need - i.e. event_dispatcher */
        }
    }