{"id":2272,"date":"2013-08-24T08:34:33","date_gmt":"2013-08-24T08:34:33","guid":{"rendered":"https:\/\/intelligentbee.com\/blog\/?p=2272"},"modified":"2024-09-30T07:36:15","modified_gmt":"2024-09-30T07:36:15","slug":"symfony2-jobeet-day-16-the-mailer","status":"publish","type":"post","link":"https:\/\/intelligentbee.com\/blog\/symfony2-jobeet-day-16-the-mailer\/","title":{"rendered":"Symfony2 Jobeet Day 16: The Mailer"},"content":{"rendered":"<h2><span style=\"font-family: timesnew roman; font-size: 12px;\">* This article is part of the original Jobeet Tutorial, created by Fabien Potencier, for Symfony 1.4.<\/span><br \/>\nMailer in jobeet<\/h2>\n<p>Yesterday, we added a read-only web service to Jobeet. Affiliates can now create an account but it needs to be activated by the administrator before it can be used. In order for the affiliate to get its token, we still need to implement the email notification. That\u2019s what we will start doing in the coming lines.<span id=\"more-195\"><\/span><\/p>\n<p>The symfony framework comes bundled with one of the best PHP emailing solution: <a href=\"http:\/\/www.swiftmailer.org\/\" target=\"_blank\" rel=\"noopener\">Swift Mailer<\/a>. Of course, the library is fully integrated with symfony, with some cool features added on top of its default features. Let\u2019s start by sending a simple email to notify the affiliate when his account has been activated and to give him the affiliate token. But first, you need to configure your environment:<\/p>\n<pre class=\"lang:yaml decode:true \" title=\"app\/config\/parameters.yml\"># ...\r\n    # ...\r\n    mailer_transport:  gmail\r\n    mailer_host:       ~\r\n    mailer_user:       address@example.com\r\n    mailer_password:   your_password\r\n    # ...<\/pre>\n<blockquote><p>For the code to work properly, you should change the <code>address@example.com<\/code> email address to a real one, along with your real password.<\/p><\/blockquote>\n<p>Do the same thing in your <code>app\/config\/parameters_test.yml<\/code> file.<\/p>\n<p>After modifying the two files, clear the cache for both test and development environment:<\/p>\n<pre class=\"toolbar:2 nums:false lang:default decode:true \">php app\/console cache:clear --env=dev\r\nphp app\/console cache:clear --env=prod<\/pre>\n<p>Because we set the mailer transport to gmail, when you will replace the email address from \u201cmailer_user\u201d, you will put a google email address.<\/p>\n<p>You can think of creating a Message as being similar to the steps you perform when you click the compose button in your mail client. You give it a subject, specify some recipients and write your message.<\/p>\n<p>To create the message, you will:<\/p>\n<ul>\n<li>call the <code>newInstance()<\/code> methond of Swift_message (refer to the Swift Mailer official <a href=\"http:\/\/www.swiftmailer.org\/docs\" target=\"_blank\" rel=\"noopener\">documentation<\/a> to learn more about this object).<\/li>\n<li>set your sender address (From:) with <code>setFrom()<\/code> method.<\/li>\n<li>set a subject line with <code>setSubject()<\/code> method.<\/li>\n<li>set recipients with one of these methods: <code>setTo()<\/code>, <code>setCc()<\/code> or <code>setBcc()<\/code>.<\/li>\n<li>set a body with <code>setBody()<\/code>.<\/li>\n<\/ul>\n<p>Replace the <code>activate<\/code> action with the following code:<\/p>\n<pre class=\"lang:php decode:true \" title=\"src\/Ibw\/JobeetBundle\/Controller\/AffiliateAdminController.php\">\/\/ ...\r\n\r\n    public function activateAction($id)\r\n    {\r\n       if($this-&gt;admin-&gt;isGranted('EDIT') === false) {\r\n            throw new AccessDeniedException();\r\n        }\r\n\r\n        $em = $this-&gt;getDoctrine()-&gt;getManager();\r\n        $affiliate = $em-&gt;getRepository('IbwJobeetBundle:Affiliate')-&gt;findOneById($id);\r\n\r\n        try {\r\n            $affiliate-&gt;setIsActive(true);\r\n            $em-&gt;flush();\r\n\r\n            $message = Swift_Message::newInstance()\r\n                -&gt;setSubject('Jobeet affiliate token')\r\n                -&gt;setFrom('address@example.com')\r\n                -&gt;setTo($affiliate-&gt;getEmail())\r\n                -&gt;setBody(\r\n                    $this-&gt;renderView('IbwJobeetBundle:Affiliate:email.txt.twig', array('affiliate' =&gt; $affiliate-&gt;getToken())))\r\n            ;\r\n\r\n            $this-&gt;get('mailer')-&gt;send($message);\r\n        } catch(Exception $e) {\r\n            $this-&gt;get('session')-&gt;setFlash('sonata_flash_error', $e-&gt;getMessage());\r\n        }\r\n\r\n        return new RedirectResponse($this-&gt;admin-&gt;generateUrl('list',$this-&gt;admin-&gt;getFilterParameters()));\r\n    }\r\n\r\n\/\/ ...<\/pre>\n<p>Sending the message is then as simple as calling the <code>send()<\/code> method on the mailer instance and passing the message as an argument.<\/p>\n<p>For the message body, we created a new file, called <code>email.txt.twig<\/code>, that contains exactly what we want to inform the affiliate about.<\/p>\n<pre class=\"lang:default decode:true\" title=\"src\/Ibw\/JobeetBundle\/Resources\/views\/Affiliate\/email.txt.twig\">Your affiliate account has been activated.\r\nYour secret token is {{affiliate}}.\r\nYou can see the jobs list at the following addresses:\r\nhttp:\/\/jobeet.local\/app_dev.php\/api\/{{affiliate}}\/jobs.xml\r\nor http:\/\/jobeet.local\/app_dev.php\/api\/{{affiliate}}\/jobs.json\r\nor http:\/\/jobeet.local\/app_dev.php\/api\/{{affiliate}}\/jobs.yaml<\/pre>\n<h3><\/h3>\n<h3>Mailer in jobeet<\/h3>\n<p>Now, let\u2019s add the mailing functionality to the <code>batchActionActivate<\/code> too, so that even if we select multiple affiliate accounts to activate, they will receive their account activation email :<\/p>\n<pre class=\"lang:php decode:true \" title=\"src\/Ibw\/JobeetBundle\/Controller\/AffiliateAdminController.php\">\/\/ ... \r\n\r\n    public function batchActionActivate(ProxyQueryInterface $selectedModelQuery)\r\n    {\r\n        \/\/ ...\r\n\r\n        try {\r\n            foreach($selectedModels as $selectedModel) {\r\n                $selectedModel-&gt;activate();\r\n                $modelManager-&gt;update($selectedModel);\r\n\r\n                $message = Swift_Message::newInstance()\r\n                    -&gt;setSubject('Jobeet affiliate token')\r\n                    -&gt;setFrom('address@example.com')\r\n                    -&gt;setTo($selectedModel-&gt;getEmail())\r\n                    -&gt;setBody(\r\n                        $this-&gt;renderView('IbwJobeetBundle:Affiliate:email.txt.twig', array('affiliate' =&gt; $selectedModel-&gt;getToken())))\r\n                ;\r\n\r\n                $this-&gt;get('mailer')-&gt;send($message);\r\n            }\r\n        } catch(Exception $e) {\r\n            $this-&gt;get('session')-&gt;setFlash('sonata_flash_error', $e-&gt;getMessage());\r\n\r\n            return new RedirectResponse($this-&gt;admin-&gt;generateUrl('list',$this-&gt;admin-&gt;getFilterParameters()));\r\n        }\r\n\r\n        \/\/ ...\r\n    }\r\n\r\n\/\/ ...<\/pre>\n<h3>The Tests<\/h3>\n<p>Now that we have seen how to send an email with the symfony mailer, let\u2019s write some functional tests to ensure we did the right thing.<\/p>\n<p>To test this new functionality, we need to be logged in. To log in, we will need an username and a password. That\u2019s why we will start by creating a new <code>fixture<\/code> file, where we add the user <code>admin<\/code>:<\/p>\n<pre class=\"lang:php decode:true \" title=\"src\/Ibw\/JobeetBundle\/DataFixtures\/ORM\/LoadUserData.php\">namespace IbwJobeetBundleDataFixturesORM;\r\n\r\nuse DoctrineCommonPersistenceObjectManager;\r\nuse DoctrineCommonDataFixturesAbstractFixture;\r\nuse DoctrineCommonDataFixturesFixtureInterface;\r\nuse DoctrineCommonDataFixturesOrderedFixtureInterface;\r\nuse SymfonyComponentDependencyInjectionContainerAwareInterface;\r\nuse SymfonyComponentDependencyInjectionContainerInterface;\r\nuse IbwJobeetBundleEntityUser;\r\n\r\nclass LoadUserData implements FixtureInterface, OrderedFixtureInterface, ContainerAwareInterface\r\n{\r\n    \/**\r\n     * @var ContainerInterface\r\n     *\/\r\n    private $container;\r\n\r\n    \/**\r\n     * {@inheritDoc}\r\n     *\/\r\n    public function setContainer(ContainerInterface $container = null)\r\n    {\r\n        $this-&gt;container = $container;\r\n    }\r\n\r\n    \/**\r\n     * @param DoctrineCommonPersistenceObjectManager $em\r\n     *\/\r\n    public function load(ObjectManager $em)\r\n    {\r\n        $user = new User();\r\n        $user-&gt;setUsername('admin');\r\n        $encoder = $this-&gt;container\r\n            -&gt;get('security.encoder_factory')\r\n            -&gt;getEncoder($user)\r\n        ;\r\n\r\n        $encodedPassword = $encoder-&gt;encodePassword('admin', $user-&gt;getSalt());\r\n        $user-&gt;setPassword($encodedPassword);\r\n\r\n        $em-&gt;persist($user);\r\n        $em-&gt;flush();\r\n    }\r\n\r\n    public function getOrder()\r\n    {\r\n        return 4; \/\/ the order in which fixtures will be loaded\r\n    }\r\n}<\/pre>\n<p>In the tests, we will use the <tt><code>swiftmailer<\/code><\/tt> collector on the profiler to get information about the messages send on the previous requests. Now, let\u2019s add some tests to check if the email is sent properly:<\/p>\n<pre class=\"lang:php decode:true \" title=\"src\/Ibw\/JobeetBundle\/Tests\/Controller\/AffiliateAdminControllerTest.php\">namespace IbwJobeetBundleTestsController;\r\n\r\nuse SymfonyBundleFrameworkBundleTestWebTestCase;\r\nuse SymfonyBundleFrameworkBundleConsoleApplication;\r\nuse SymfonyComponentConsoleOutputNullOutput;\r\nuse SymfonyComponentConsoleInputArrayInput;\r\nuse DoctrineBundleDoctrineBundleCommandDropDatabaseDoctrineCommand;\r\nuse DoctrineBundleDoctrineBundleCommandCreateDatabaseDoctrineCommand;\r\nuse DoctrineBundleDoctrineBundleCommandProxyCreateSchemaDoctrineCommand;\r\n\r\nclass AffiliateAdminControllerTest extends WebTestCase\r\n{\r\n    private $em;\r\n    private $application;\r\n\r\n    public function setUp()\r\n    {\r\n        static::$kernel = static::createKernel();\r\n        static::$kernel-&gt;boot();\r\n\r\n        $this-&gt;application = new Application(static::$kernel);\r\n\r\n        \/\/ drop the database\r\n        $command = new DropDatabaseDoctrineCommand();\r\n        $this-&gt;application-&gt;add($command);\r\n        $input = new ArrayInput(array(\r\n            'command' =&gt; 'doctrine:database:drop',\r\n            '--force' =&gt; true\r\n        ));\r\n        $command-&gt;run($input, new NullOutput());\r\n\r\n        \/\/ we have to close the connection after dropping the database so we don't get \"No database selected\" error\r\n        $connection = $this-&gt;application-&gt;getKernel()-&gt;getContainer()-&gt;get('doctrine')-&gt;getConnection();\r\n        if ($connection-&gt;isConnected()) {\r\n            $connection-&gt;close();\r\n        }\r\n\r\n        \/\/ create the database\r\n        $command = new CreateDatabaseDoctrineCommand();\r\n        $this-&gt;application-&gt;add($command);\r\n        $input = new ArrayInput(array(\r\n            'command' =&gt; 'doctrine:database:create',\r\n        ));\r\n        $command-&gt;run($input, new NullOutput());\r\n\r\n        \/\/ create schema\r\n        $command = new CreateSchemaDoctrineCommand();\r\n        $this-&gt;application-&gt;add($command);\r\n        $input = new ArrayInput(array(\r\n            'command' =&gt; 'doctrine:schema:create',\r\n        ));\r\n        $command-&gt;run($input, new NullOutput());\r\n\r\n        \/\/ get the Entity Manager\r\n        $this-&gt;em = static::$kernel-&gt;getContainer()\r\n            -&gt;get('doctrine')\r\n            -&gt;getManager();\r\n\r\n        \/\/ load fixtures\r\n        $client = static::createClient();\r\n        $loader = new SymfonyBridgeDoctrineDataFixturesContainerAwareLoader($client-&gt;getContainer());\r\n        $loader-&gt;loadFromDirectory(static::$kernel-&gt;locateResource('@IbwJobeetBundle\/DataFixtures\/ORM'));\r\n        $purger = new DoctrineCommonDataFixturesPurgerORMPurger($this-&gt;em);\r\n        $executor = new DoctrineCommonDataFixturesExecutorORMExecutor($this-&gt;em, $purger);\r\n        $executor-&gt;execute($loader-&gt;getFixtures());\r\n    }\r\n\r\n    public function testActivate()\r\n    {\r\n        $client = static::createClient();\r\n\r\n        \/\/ Enable the profiler for the next request (it does nothing if the profiler is not available)\r\n        $client-&gt;enableProfiler();\r\n        $crawler = $client-&gt;request('GET', '\/login');\r\n\r\n        $form = $crawler-&gt;selectButton('login')-&gt;form(array(\r\n            '_username'      =&gt; 'admin',\r\n            '_password'      =&gt; 'admin'\r\n        ));\r\n\r\n        $crawler = $client-&gt;submit($form);\r\n        $crawler = $client-&gt;followRedirect();\r\n\r\n        $this-&gt;assertTrue(200 === $client-&gt;getResponse()-&gt;getStatusCode());\r\n\r\n        $crawler = $client-&gt;request('GET', '\/admin\/ibw\/jobeet\/affiliate\/list');\r\n\r\n        $link = $crawler-&gt;filter('.btn.edit_link')-&gt;link();\r\n        $client-&gt;click($link);\r\n\r\n        $mailCollector = $client-&gt;getProfile()-&gt;getCollector('swiftmailer');\r\n\r\n        \/\/ Check that an e-mail was sent\r\n        $this-&gt;assertEquals(1, $mailCollector-&gt;getMessageCount());\r\n\r\n        $collectedMessages = $mailCollector-&gt;getMessages();\r\n        $message = $collectedMessages[0];\r\n\r\n        \/\/ Asserting e-mail data\r\n        $this-&gt;assertInstanceOf('Swift_Message', $message);\r\n        $this-&gt;assertEquals('Jobeet affiliate token', $message-&gt;getSubject());\r\n        $this-&gt;assertRegExp(\r\n            '\/Your secret token is symfony\/',\r\n            $message-&gt;getBody()\r\n        );\r\n    }\r\n}<\/pre>\n<p>If you run the test now, you\u2019ll get and error. To prevent this for happening, go to your <code>config_test.yml<\/code> file and make sure that the profiler is enabled in the test environment. If it\u2019s set to <code>false<\/code>, change it to <code>true<\/code>:<\/p>\n<pre class=\"lang:yaml decode:true \" title=\"app\/config\/config_test.yml\"># ...\r\n\r\nframework:\r\n    test: ~\r\n    session:\r\n        storage_id: session.storage.mock_file\r\n    profiler:\r\n        enabled: true\r\n\r\n# ...<\/pre>\n<p>Now, clear the cache, run the test command in your console and enjoy the green bar :<\/p>\n<pre class=\"toolbar:2 nums:false lang:default decode:true \">phpunit -c app src\/Ibw\/JobeetBundle\/Tests\/Controller\/AffiliateAdminControllerTest<\/pre>\n<p><a href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/3.0\/\" rel=\"license\"><img decoding=\"async\" style=\"border-width: 0;\" src=\"\/\/i.creativecommons.org\/l\/by-sa\/3.0\/88x31.png\" alt=\"Creative Commons License\" \/><\/a><br \/>\nThis work is licensed under a <a href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/3.0\/\" target=\"_blank\" rel=\"license noopener\">Creative Commons Attribution-ShareAlike 3.0 Unported License<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>* This article is part of the original Jobeet Tutorial, created by Fabien Potencier, for Symfony 1.4. Mailer in jobeet [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[82],"tags":[],"yst_prominent_words":[483,528,545,564,977,983,1013,1063,1224,1395,2283],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts\/2272"}],"collection":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/comments?post=2272"}],"version-history":[{"count":3,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts\/2272\/revisions"}],"predecessor-version":[{"id":133224,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts\/2272\/revisions\/133224"}],"wp:attachment":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/media?parent=2272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/categories?post=2272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/tags?post=2272"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/yst_prominent_words?post=2272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}