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

Inyectar templating en un servicio

15 de julio de 2015

Hola, estoy haciendo un servicio que me compare si existe un registro relacionado en una entidad. Si existe un registro, se debe enviar un correo al usuario. El servicio funciona, lo que quiero lograr es que el correo que envía sea una plantilla twig.

Esto fue lo que hice inicialmente:

$message = $mailer->createMessage()
    ->setSubject('Hemos recibido su mensaje')
    ->setFrom('[email protected]')
    ->setTo('[email protected]')
    ->setBody(
        $this->renderView(
            'Emails/correo.html.twig',
            array('pre' => $pre)
        ),
        'text/html'
    )
;

El código anterior me arroja el siguiente error :

Attempted to call an undefined method named "renderView"

Se me ocurrio inyectar @templating en el servicio pero me arroja otro error:

Circular reference detected for service "security.authentication.manager", path: 
"security.firewall.map.context.main -> security.authentication.manager -> 
fos_user.user_provider.username_email -> fos_user.user_manager -> fos_user.entity_manager -> 
doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> 
galaxy_cargo_warehouse.whnumber -> templating -> twig -> security.authorization_checker".

Este es mi servicio

acme.whnumber:
    class: AcmeBundle\EventListener\GenerateWhnumber
    arguments: [ @mailer, @templating ]
    tags:
        - { name: doctrine.event_listener, event: postPersist }

Mis dudas son, ¿se puede enviar un correo con Swiftmailer desde una plantilla de Twig? ¿Cómo inyecto @templating para ver si me funciona?

Les agradezco la ayuda.


Respuestas

#1

Hace unos días planteé una mejora en Symfony precisamente para poder enviar emails renderizando una plantilla Twig. Aquí puedes ver los detalles. A ver si con un poco de suerte se incluye en las próximas versiones.

Normalmente, inyectar el servicio @templating funciona perfectamente. De hecho, este sitio web en el que te encuentras, está desarrollado con Symfony y envío emails con plantillas renderizadas. Para ello inyecto el servicio @templating.

En tu caso, por alguna razón, alguno de tus servicios hace uso del servicio security.authorization_checker y eso crea una referencia circular: un servicio usa otro servicio, que a su vez usa otro servicio diferente, ..., hasta que el último servicio utiliza a su vez el primer servicio. Este tipo de referencias circulares no se pueden resolver automáticamente, pero Symfony te avisa que se están produciendo.

En esta respuesta de StackOverflow recomiendan como solución que inyectes todo el contenedor de servicios en vez de @templating. Así que prueba a inyectar @service_container a ver si se soluciona. Por supuesto esta es una mala práctica que se desaconseja salvo en situaciones extremas.

Por último, si tienes tiempo de cambiar un poco tu aplicación, lo que te aconsejo es que dividas en dos servicios este servicio que hace dos cosas diferentes. El servicio actual debería mantener la lógica que decide si hay que notificar al usuario, pero la notificación concreta (el envío del email) podría estar definido en otro servicio. Para enviar la notificación, puedes inyectar el otro servicio y ejecutar un determinado método a mano, o puedes usar eventos para desacoplar todavía más esos dos servicios.

@javiereguiluz

15 julio 2015, 8:42
#2

@miguelplazasr preciso como dice @javier lo de separar las tareas en servicios fue la solución que le he dado a ese problema. La mejor solución, por ahora.

Lo primero que hice fue crear una capa (servicio) de las actividades normales que se usan al envíar un mail y es el de instanciar el servicio Mailer()

Luego, este servicio lo inyecto en donde lo necesite o lo uso en el Controller: $this->get('mailer_service')->msn('mailer@example', 'Mi mensaje');

Para renderizar la plantilla y pasársela al servicio uso \Twig_Environment y se lo adhiero al MailerService como cuerpo del mensaje:

<?php 
 
...
 
use AppBundle\Utils\MailerService;
use \Twig_Environment as Environment;
 
class MyClase
{
  private $mailer;
  private $twig;
 
  public function __construct(MailerService $mailer, Environment $twig)
  {
    $this->mailer = $mailer;
    $this->twig   = $twig;
  }
 
  public function myMetodo()
  {
    /**
    * Acá toda la lógica
    */
    ...
 
    $msn = $this->twig->render('Ruta/Hasta/La/Plantilla', array('parametro', $valor));
    $this->mailer->msn('[email protected]', $msn);
 
  }
 
}
?>

Así he desacoplado las dos actividades. Espero le sirva. Un saludo

@cristian_angulo

15 julio 2015, 16:16
#3

Hola, les agradezco la ayuda, realmente me sirvio,

Saludos

@miguelplazasr

8 agosto 2015, 0:51