Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Como enviar emails fuera del controlador en Symfony

13 de abril de 2015

Buenas noches.

Tengo los controladores muy cargados de código y quiero dejarlos más limpios desacoplando acciones. Por ejemplo, creando una clase para enviar distintos tipos de correos, pero no se cómo hacerlo.

He estado revisando la documentación de Symfony pero no he encontrado la manera de hacerlo, creando un servicio, un evento, ... Espero me puedan orientar porque llevo unos días dándole vueltas y no se cómo hacerlo.

Este método lo que hace es enviar un email de contacto al administrador. Mi idea es crear una clase con distintos tipos de emails, email con un nuevo usuario registrado, email avisando cuando un usuario crea un nuevo producto, ... y poder usarlo en cualquier parte.

Pego parte del código del controlador:

public function contactAction(Request $request)
  {
    $user        = new User();
    $contactForm = $this->createForm(new ContactType());
    $contactForm->handleRequest($request);
 
    if($contactForm->isValid())
    {
      $data    = $contactForm->getData();
      $mailer  = $this->get('mailer');
      $message = $mailer->createMessage()
        ->setSubject('Formulario de contacto')
        ->setFrom('[email protected]')
        ->setTo(array('[email protected]' => '[email protected]'))
        ->setBody($this->renderView('AppBundle:Account:contactTemplate.html.twig',
          array('name'    => $data['name'],
                'mail'    => $data['mail'],
                'content' => $data['content']
          )
        ));
      $mailer->send($message);
 
      $request->getSession()->getFlashBag()->add(
        'notice',
        $this->get('translator')->trans('flash.contact', array(), 'messages'
      ));
 
      return $this->redirect($this->generateUrl('contact'));
    }
 
    return $this->render('AppBundle:account:contact.html.twig', array(
        'form' => $contactForm->createView()
    ));
  }

Un saludo.


Respuestas

#1

@nonio_87 como parece que ya tienes suficiente experiencia con Symfony, te indico en plan general cómo lo hago yo por si te sirve de ayuda. Luego si tienes alguna duda concreta, dímelo y entramos en detalles de implementación.

La primera forma de implementarlo sería crear un servicio app.mailer y usarlo en el controlador así:

$this->get('app.mailer')->sendContactMessage($content);

La otra forma sería utilizar eventos y en el controlador simplemente lanzar el evento adecuado y luego crear un listener que escuche el evento:

use Symfony\Component\EventDispatcher\GenericEvent;
 
$event = new GenericEvent(array('content' => $content));
$dispatcher->dispatch('email.contacto', $event);

Ahora viene lo importante, ¿cómo hacer ese mailer? Yo lo que hice fue coger el mailer de FOSUserBundle y simplificarlo bastante.

  • Definición del servicio yo sólo he implementado el mailer de tipo TwigSwiftMailer porque es el único que voy a usar en la aplicación (este servicio lo defino en YAML en el archivo app/config/config.yml). En mi caso lo he simplificado para sólo pasarle el servicio twig y el servicio mailer. Todo lo demás lo quito para simplificar las cosas.
  • Código del mailer. De nuevo yo lo simplifico bastante. En vez de crear métodos auxiliares (como por ejemplo sendConfirmationEmailMessage()) yo sólo defino el método genérico sendMessage($templateName, $context, $fromEmail, $toEmail). Con este método ya puedo hacer lo que quiera.
  • Plantillas de los emails yo las guardo todas en app/Resources/views/email/. Así tengo todo centralizado y las rutas de las plantillas son tan fáciles como email/contacto.html.twig. Una cosa que me parece genial de FOSUserBundle es que define varios bloques de Twig en la plantilla para definir tanto el asunto como el contenido en formato HTML y TXT. Me parece una solución muy elegante que permite definir todo el contenido del email en la misma plantilla. Luego en el código del mailer verás que renderiza cada bloque por separado para obtener el contenido de cada parte del email.

@javiereguiluz

14 abril 2015, 8:41
#2

Gracias por responder.

Experiencia tengo más bien un nivel básico. Este es mi primer proyecto con Symfony y decir que lo que he aprendido ha sido usando de guía tu libro de desarrollo web ágil con symfony 2 y la documentación oficial jejeje.

He revisado FOSUserBundle pero no termino de saber cómo aplicar lo que dices. Es la primera vez que voy a trabajar con eventos y no lo tengo claro. ¿Podrías explicarme si no te importa un poco más a fondo como hacerlo?

@nonio_87

15 abril 2015, 1:59
#4

@nonio_87, los links de @manuel_j555 están genial, pero mi consejo sería que empezaras a implementar esta funcionalidad sin los eventos. Cuando ya tengas el mailer funcionando bien, pasarte a los eventos sera muy sencillo. Pero hacer todo a la vez puede complicar las cosas más de lo necesario.

@javiereguiluz

15 abril 2015, 15:31
#5

Ya conseguí tener mis emails fuera y además he creado un manager para sacar la lógica del controlador, conteniendo aún menos líneas de código. Muchas gracias Javier y Manuel_j555.

@nonio_87

19 abril 2015, 23:27
#6

@nonio_87 ¿Podrías publicar cómo lo has conseguido?

@devforideas

9 marzo 2017, 12:20