Symfony2 - Jobeet - Jour 16 - Les e-mails

1 1 1 1 1 1 1 1 1 1 Rating 0.00 (0 Votes)
Submit to DeliciousSubmit to DiggSubmit to FacebookSubmit to Google PlusSubmit to StumbleuponSubmit to TechnoratiSubmit to TwitterSubmit to LinkedIn

Hier, nous avons ajouté un service Web en lecture pour Jobeet. Les affiliés peuvent désormais créer un compte mais il doit être activé par l'administrateur avant de pouvoir être utilisé. Pour que l'affilié obtienne son jeton, nous avons encore besoin de mettre en œuvre la notification par email. C'est ce que nous allons commencer à faire dans les lignes à venir. Le framework symfony est livré avec l'une des meilleures solutions d'e-mailing de PHP : Swift Mailer. Bien sûr, la bibliothèque est entièrement intégré à symfony, avec quelques fonctionnalités intéressantes ajoutées au-dessus de ses fonctions par défaut. Commençons par l'envoi d'un simple e-mail pour informer l'affilié lorsque son compte a été activé et de lui donner le jeton de l'affiliation. Mais d'abord, vous devez configurer votre environnement :

  • app/config/parameters.yml
# ...
    # ...
    mailer_transport:  gmail
    mailer_host:       ~
    mailer_user:       address[at]example.com
    mailer_password:   your_password
    # ...

Pour que le code fonctionne correctement, vous devez changer l'adresse e-mail (address[at]example.com) ainsi que le mot de passe (your_password).

Faites la même chose dans le fichier app/config/parameters_test.yml :

  • app/config/parameters_test.yml
# ...
    # ...
    mailer_transport:  gmail
    mailer_host:       ~
    mailer_user:       address[at]example.com
    mailer_password:   your_password
    # ...

Après avoir modifié les deux fichiers, effacer le cache à la fois pour l'environnement de test et de développement :

php app/console cache:clear --env=dev
php app/console cache:clear --env=prod

Parce que nous utilisons gmail, lorsque vous allez remplacer l'adresse email "mailer_user", vous allez mettre une adresse google mail.
Vous pouvez penser à la création d'un message comme étant similaire aux étapes que vous effectuez lorsque vous cliquez sur le bouton de composition dans votre client de messagerie. Vous lui donnez un sujet, spécifier les bénéficiaires et écrivez votre message.
Pour créer le message, vous devrez :

  • appeler le methond newInstance() de Swift_message (reportez-vous à la documentation officielle de Swift Mailer pour en savoir plus sur cet objet).
  • pour définir l'adresse de l'expéditeur (De :) avec la méthode setFrom()
  • définir l'objet avec la méthode setSubject()
  • définir les destinataires d'une de ces méthodes : setTo(), setCc() or setBcc().
  • définir un corps avec setBody(). 

Dans les codes ci-dessous, remplacez les [at] par des @.

Remplacer l'action activation par le code suivant :

  •  src/Erlem/JobeetBundle/Controller/AffiliateAdminController.php
// ...

    public function activateAction($id)
    {
       if($this->admin->isGranted('EDIT') === false) {
            throw new AccessDeniedException();
        }
 
        $em = $this->getDoctrine()->getManager();
        $affiliate = $em->getRepository('ErlemJobeetBundle:Affiliate')->findOneById($id);
 
        try {
            $affiliate->setIsActive(true);
            $em->flush();
 
            $message = \Swift_Message::newInstance()
                ->setSubject('Jobeet affiliate token')
                ->setFrom('address[at]example.com')
                ->setTo($affiliate->getEmail())
                ->setBody(
                    $this->renderView('ErlemJobeetBundle:Affiliate:email.txt.twig', array('affiliate' => $affiliate->getToken())))
            ;
 
            $this->get('mailer')->send($message);
        } catch(\Exception $e) {
            $this->get('session')->getFlashBag()->add('sonata_flash_error', $e->getMessage());
        }
 
        return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
    }

// ...

L'envoi du message est donc aussi simple que d'appeler la méthode send() et passer le message comme argument.
Pour le corps du message, nous avons créé un nouveau fichier, appelé email.txt.twig.

  •  src/Erlem/JobeetBundle/Resources/views/Affiliate/email.txt.twig
Your affiliate account has been activated.
Your secret token is {{affiliate}}.
You can see the jobs list at the following addresses:
http://jobeet.local/app_dev.php/api/{{affiliate}}/jobs.xml
or http://jobeet.local/app_dev.php/api/{{affiliate}}/jobs.json
or http://jobeet.local/app_dev.php/api/{{affiliate}}/jobs.yaml

Maintenant, nous allons ajouter la fonctionnalité de diffusion de la batchActionActivate, de sorte que même si nous sélectionnons plusieurs comptes d'affiliation pour activer, ils recevront leur compte de courriel d'activation :

  •  src/Erlem/JobeetBundle/Controller/AffiliateAdminController.php
// ... 

    public function batchActionActivate(ProxyQueryInterface $selectedModelQuery)
    {
        // ...

        try {
            foreach($selectedModels as $selectedModel) {
                $selectedModel->activate();
                $modelManager->update($selectedModel);

                $message = \Swift_Message::newInstance()
                    ->setSubject('Jobeet affiliate token')
                    ->setFrom('address[at]example.com')
                    ->setTo($selectedModel->getEmail())
                    ->setBody(
                        $this->renderView('ErlemJobeetBundle:Affiliate:email.txt.twig', array('affiliate' => $selectedModel->getToken())))
                ;

                $this->get('mailer')->send($message);
            }
        } catch(\Exception $e) {
            $this->get('session')->setFlash('sonata_flash_error', $e->getMessage());

            return new RedirectResponse($this->admin->generateUrl('list',$this->admin->getFilterParameters()));
        }

        // ...
    }

// ...

Pour tester l'envoi de mails, complétez le formulaire "Become an affiliate" :

01-115-symfony2-jobeet-jour-16-les-e-mails

Un message de confirmation apparaît :

02-115-symfony2-jobeet-jour-16-les-e-mails

Ensuite allez dans la partie administrative puis cliquez sur le bouton "activate" pour valider l'email :

03-115-symfony2-jobeet-jour-16-les-e-mails

Un mail vous êtes ensuite envoyé, regardez votre messagerie :

03b-115-symfony2-jobeet-jour-16-les-e-mails

Les tests

Maintenant que nous avons vu comment envoyer un email avec le mailer de symfony, nous allons écrire des tests fonctionnels pour s'assurer que tout fonnctionne correctement.
Pour tester cette nouvelle fonctionnalité, nous devons être connecté. Pour vous connecter, nous aurons besoin d'un nom d'utilisateur et un mot de passe. C'est pourquoi nous allons commencer par créer un nouveau fichier de fixure, où l'on ajoute l'utilisateur admin :

  • src/Erlem/JobeetBundle/DataFixtures/ORM/LoadUserData.php
namespace Erlem\JobeetBundle\DataFixtures\ORM;

use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Erlem\JobeetBundle\Entity\User;

class LoadUserData implements FixtureInterface, OrderedFixtureInterface, ContainerAwareInterface
{
    /**
     * @var ContainerInterface
     */
    private $container;

    /**
     * {@inheritDoc}
     */
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    /**
     * @param \Doctrine\Common\Persistence\ObjectManager $em
     */
    public function load(ObjectManager $em)
    {
        $user = new User();
        $user->setUsername('admin');
        $encoder = $this->container
            ->get('security.encoder_factory')
            ->getEncoder($user)
        ;

        $encodedPassword = $encoder->encodePassword('admin', $user->getSalt());
        $user->setPassword($encodedPassword);

        $em->persist($user);
        $em->flush();
    }

    public function getOrder()
    {
        return 4; // the order in which fixtures will be loaded
    }
}

Dans les tests, nous allons utiliser le collecteur de swiftmailer sur le profileur pour obtenir des informations concernant les messages des demandes précédentes. Maintenant, nous allons ajouter quelques tests pour vérifier si le courriel est envoyé correctement :

  • src/Erlem/JobeetBundle/Tests/Controller/AffiliateAdminControllerTest.php
<?php

namespace Erlem\JobeetBundle\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Input\ArrayInput;
use Doctrine\Bundle\DoctrineBundle\Command\DropDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\CreateDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\CreateSchemaDoctrineCommand;

class AffiliateAdminControllerTest extends WebTestCase
{
    private $em;
    private $application;

    public function setUp()
    {
        static::$kernel = static::createKernel();
        static::$kernel->boot();

        $this->application = new Application(static::$kernel);

        // drop the database
        $command = new DropDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:drop',
            '--force' => true
        ));
        $command->run($input, new NullOutput());

        // we have to close the connection after dropping the database so we don't get "No database selected" error
        $connection = $this->application->getKernel()->getContainer()->get('doctrine')->getConnection();
        if ($connection->isConnected()) {
            $connection->close();
        }

        // create the database
        $command = new CreateDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:create',
        ));
        $command->run($input, new NullOutput());

        // create schema
        $command = new CreateSchemaDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:schema:create',
        ));
        $command->run($input, new NullOutput());

        // get the Entity Manager
        $this->em = static::$kernel->getContainer()
            ->get('doctrine')
            ->getManager();

        // load fixtures
        $client = static::createClient();
        $loader = new \Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader($client->getContainer());
        $loader->loadFromDirectory(static::$kernel->locateResource('@ErlemJobeetBundle/DataFixtures/ORM'));
        $purger = new \Doctrine\Common\DataFixtures\Purger\ORMPurger($this->em);
        $executor = new \Doctrine\Common\DataFixtures\Executor\ORMExecutor($this->em, $purger);
        $executor->execute($loader->getFixtures());
    }

    public function testActivate()
    {
        $client = static::createClient();

        // Enable the profiler for the next request (it does nothing if the profiler is not available)
        $client->enableProfiler();
        $crawler = $client->request('GET', '/login');

        $form = $crawler->selectButton('login')->form(array(
            '_username'      => 'admin',
            '_password'      => 'admin'
        ));

        $crawler = $client->submit($form);
        $crawler = $client->followRedirect();

        $this->assertTrue(200 === $client->getResponse()->getStatusCode());

        $crawler = $client->request('GET', '/admin/erlem/jobeet/affiliate/list');

        $link = $crawler->filter('.btn.edit_link')->link();
        $client->click($link);

        $mailCollector = $client->getProfile()->getCollector('swiftmailer');

        // Check that an e-mail was sent
        $this->assertEquals(1, $mailCollector->getMessageCount());

        $collectedMessages = $mailCollector->getMessages();
        $message = $collectedMessages[0];

        // Asserting e-mail data
        $this->assertInstanceOf('Swift_Message', $message);
        $this->assertEquals('Jobeet affiliate token', $message->getSubject());
        $this->assertRegExp(
            '/Your secret token is symfony/',
            $message->getBody()
        );
    }
}

Si vous exécutez le test maintenant, vous obtiendrez l'erreur. Pour éviter que cela arrive, aller dans le fichier config_test.yml et assurez-vous que le "profiler" est activé dans l'environnement de test. Si elle est définie sur false, changer en true :

  • app/config/config_test.yml
# ...

framework:
    test: ~
    session:
        storage_id: session.storage.mock_file
    profiler:
        enabled: true

# ...

Maintenant, vider le cache, exécutez la commande de test dans votre console :

phpunit -c app src/Erlem/JobeetBundle/Tests/Controller/AffiliateAdminControllerTest

Symfony2 - Jour 15 - Services Web
[Sommaire] Symfony2 - Jour 17 - Recherche >


Pour ce tutoriel, je me suis inspiré du tutoriel Symfony2 Jobeet du site IntelligentBee

Submit to DeliciousSubmit to DiggSubmit to FacebookSubmit to Google PlusSubmit to StumbleuponSubmit to TechnoratiSubmit to TwitterSubmit to LinkedIn