Correo electrónico desde el comando CLI
Ya hemos hecho el trabajo previo para nuestra función de correo electrónico recordatorio. Ahora, ¡vamos a crear y enviar los correos!
Plantilla de correo electrónico recordatorio
En templates/email, la nueva plantilla de correo electrónico será muy similar abooking_confirmation.html.twig. Copia ese archivo y nómbralo booking_reminder.html.twig. Dentro, no quiero perder demasiado tiempo en esto, así que simplemente cambia el título del acento para que diga "¡Próximamente!":
| {% extends 'email/layout.html.twig' %} | |
| {% block content %} | |
| <row> | |
| <columns> | |
| <spacer size="40"></spacer> | |
| <p class="accent-title">Coming soon!</p> | |
| <h1 class="trip-name">{{ trip.name }}</h1> | |
| <img | |
| class="trip-image float-center" | |
| src="{{ email.image('@images/%s.png'|format(trip.slug)) }}" | |
| alt="{{ trip.name }}"> | |
| </columns> | |
| </row> | |
| <row> | |
| <columns> | |
| <p class="accent-title">Departure: {{ booking.date|date('Y-m-d') }}</p> | |
| </columns> | |
| </row> | |
| <row> | |
| <columns> | |
| <button class="expanded rounded center" href="{{ url('booking_show', {uid: booking.uid}) }}"> | |
| Manage Booking | |
| </button> | |
| <button class="expanded rounded center secondary" href="{{ url('bookings', {uid: customer.uid}) }}"> | |
| My Account | |
| </button> | |
| </columns> | |
| </row> | |
| {% endblock %} |
¡Envíalo! ¡Juego de palabras espacial accidental!
Comando Enviar Recordatorio
La lógica para enviar los correos electrónicos tiene que ser algo que podamos programar para que se ejecute cada hora o cada día. ¡El trabajo perfecto para un comando CLI! En tu terminal, ejecuta:
symfony make:command
¡Bah!
symfony console make:command
Llámalo: app:send-booking-reminders.
¡Ve a comprobarlo! src/Command/SendBookingRemindersCommand.php. Cambia la descripción a "Enviar correos electrónicos de recordatorio de reserva":
| // ... lines 1 - 17 | |
| ( | |
| // ... line 19 | |
| description: 'Send booking reminder emails', | |
| ) | |
| class SendBookingRemindersCommand extends Command | |
| // ... lines 23 - 70 |
En el constructor, autocablea y establece propiedades para BookingRepository, EntityManagerInterfacey MailerInterface:
| // ... lines 1 - 21 | |
| class SendBookingRemindersCommand extends Command | |
| { | |
| public function __construct( | |
| private BookingRepository $bookingRepo, | |
| private EntityManagerInterface $em, | |
| private MailerInterface $mailer, | |
| ) { | |
| parent::__construct(); | |
| } | |
| // ... lines 31 - 68 | |
| } |
Este comando no necesita argumentos ni opciones, así que elimina por completo el método configure().
Limpia las tripas de execute(). Empieza añadiendo un bonito:$io->title('Sending booking reminders'). Luego, coge las reservas que necesitan que se envíen recordatorios, con $bookings = $this->bookingRepo->findBookingsToRemind().
Barra de progreso fácil
Para ser los mejores, mostremos una barra de progreso mientras recorremos las reservas. El objeto $io tiene un truco para esto. Escribe foreach ($io->progressIterate($bookings) as $booking). Esto se encarga de toda la aburrida lógica de la barra de progreso Dentro, tenemos que crear un nuevo correo electrónico. En TripController, copia ese correo electrónico -incluyendo estas cabeceras- y pégalo aquí.
Pero tenemos que ajustarlo un poco: elimina el archivo adjunto. Y para el asunto: sustituye "Confirmación" por "Recordatorio". Arriba, añade algunas variables por comodidad:$customer = $booking->getCustomer() y $trip = $booking->getTrip(). Aquí abajo, mantén los mismos metadatos, pero cambia la etiqueta a booking_reminder. Esto nos ayudará a distinguir mejor estos correos en Mailtrap.
Ah, y por supuesto, cambia la plantilla a booking_reminder.html.twig.
Siguiendo con el bucle, envía el correo electrónico con $this->mailer->send($email) y marca la reserva como recordatorio enviado con$booking->setReminderSentAt(new \DateTimeImmutable('now')).
¡Perfecto! Fuera del bucle, llama a $this->em->flush() para guardar los cambios en la base de datos. Por último, celébralo con$io->success(sprintf('Sent %d booking reminders', count($bookings))).
| // ... lines 1 - 21 | |
| class SendBookingRemindersCommand extends Command | |
| { | |
| // ... lines 24 - 31 | |
| protected function execute(InputInterface $input, OutputInterface $output): int | |
| { | |
| $io = new SymfonyStyle($input, $output); | |
| $io->title('Sending booking reminders'); | |
| $bookings = $this->bookingRepo->findBookingsToRemind(); | |
| foreach ($io->progressIterate($bookings) as $booking) { | |
| $trip = $booking->getTrip(); | |
| $customer = $booking->getCustomer(); | |
| $email = (new TemplatedEmail()) | |
| ->to(new Address($customer->getEmail())) | |
| ->subject('Booking Reminder for '.$trip->getName()) | |
| ->htmlTemplate('email/booking_reminder.html.twig') | |
| ->context([ | |
| 'customer' => $customer, | |
| 'trip' => $trip, | |
| 'booking' => $booking, | |
| ]) | |
| ; | |
| $email->getHeaders()->add(new TagHeader('booking_reminder')); | |
| $email->getHeaders()->add(new MetadataHeader('booking_uid', $booking->getUid())); | |
| $email->getHeaders()->add(new MetadataHeader('customer_uid', $customer->getUid())); | |
| $this->mailer->send($email); | |
| $booking->setReminderSentAt(new \DateTimeImmutable('now')); | |
| } | |
| $this->em->flush(); | |
| $io->success(sprintf('Sent %d booking reminders', count($bookings))); | |
| return Command::SUCCESS; | |
| } | |
| } |
¡Hora de probar! Ve a tu terminal. Para asegurarte de que tenemos una reserva que necesita que se le envíe un recordatorio, recarga los accesorios con:
symfony console doctrine:fixture:load
Ahora, ¡ejecuta nuestro nuevo comando!
symfony console app:send-booking-reminders
Bien, ¡se ha enviado 1 recordatorio! Y el resultado impresionará a nuestros colegas! Antes de comprobar Mailtrap, vuelve a ejecutar el comando:
symfony console app:send-booking-reminders
"Enviados 0 recordatorios de reserva". ¡Perfecto! Nuestra lógica para marcar las reservas como recordatorios enviados ¡funciona!
Ahora comprueba Mailtrap... ¡aquí está! Como era de esperar, se parece mucho a nuestro correo de confirmación, pero aquí dice "Próximamente": está utilizando la nueva plantilla.
X-Tag y X-Metadata
Cuando se utiliza "Prueba de Mailtrap", las etiquetas y metadatos de Mailer no se convierten en categorías y variables personalizadas de Mailtrap, como ocurre cuando se envían en producción. ¡Pero aún puedes asegurarte de que se envían! Haz clic en esta pestaña "Información técnica" y desplázate un poco hacia abajo. Cuando Mailer no sabe cómo convertir las etiquetas y los metadatos, los añade como estas cabeceras genéricas personalizadas: X-Tag y X-Metadata.
Efectivamente, X-Tag es booking_reminder. Genial, ¡eso es lo que esperamos también!
Vale, ¿nueva función? ¡Comprobado! ¿Pruebas para la nueva función? ¡Eso a continuación!
bye "console"