Diseño Twig de correo electrónico
Lucky you! You found an early release chapter - it will be fully polished and published shortly!
This Chapter isn't quite ready...
Rest assured, the gnomes are hard at work
completing this video!
¡Hora de una nueva función! Quiero enviar un correo electrónico recordatorio a los clientes 1 semana antes de su viaje reservado. ¡T menos 1 semana para despegar gente!
Problema con el Trabajador CLI de Symfony
En primer lugar, tenemos un pequeño problema con nuestro Symfony CLI worker. Abre.symfony.local.yaml
. Nuestro trabajador messenger
está buscando cambios en el directorio vendor
. Al menos en algunos sistemas, hay demasiados archivos aquí para monitorizar y ocurren cosas raras. No pasa nada: elimina vendor/
:
workers: | |
// ... lines 2 - 5 | |
messenger: | |
// ... line 7 | |
watch: ['config', 'src', 'templates'] |
Y como hemos cambiado la configuración, salta a tu terminal y reinicia el servidor web:
symfony server:stop
Y
symfony serve -d
Diseño del correo electrónico
Nuestro nuevo correo electrónico de recordatorio de reserva tendrá una plantilla muy similar a la de confirmación de reserva. Para reducir la duplicación, y mantener la coherencia de nuestros elegantes correos electrónicos, en templates/email/
, crea una nueva plantilla layout.html.twig
a la que se extenderán todos nuestros correos electrónicos.
Copia el contenido de booking_confirmation.html.twig
y pégalo aquí. Ahora, elimina el contenido específico de confirmación de reserva y crea un bloque content
vacío. Creo que está bien mantener nuestra firma aquí.
{% apply inky_to_html|inline_css(source('@styles/foundation-emails.css'), source('@styles/email.css')) %} | |
<container> | |
{% block content %}{% endblock %} | |
<row> | |
<columns> | |
<p>We can't wait to see you there,</p> | |
<p>Your friends at Universal Travel</p> | |
</columns> | |
</row> | |
</container> | |
{% endapply %} |
En booking_confirmation.html.twig
, aquí arriba, amplía este nuevo diseño y añade el bloquecontent
. Abajo, copia el contenido específico del correo electrónico y pégalo dentro de ese bloque. Elimina todo lo demás.
{% extends 'email/layout.html.twig' %} | |
{% block content %} | |
<row> | |
<columns> | |
<spacer size="40"></spacer> | |
<p class="accent-title">Get Ready for your trip to</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 %} |
Asegurémonos de que el correo electrónico de confirmación de la reserva sigue funcionando, ¡y tenemos pruebas para ello! De vuelta en el terminal, ejecútalas con:
bin/phpunit
¡Verde! Eso es buena señal. Asegurémonos doblemente comprobándolo en Mailtrap. En la aplicación, reserva un viaje... y comprueba Mailtrap. ¡Sigue estando fantástico!
¡Es hora de enviar el correo electrónico recordatorio!
Indicador de recordatorio de reserva
Después de enviar un correo electrónico recordatorio, tenemos que marcar la reserva para no molestar al cliente con múltiples recordatorios. Vamos a añadir una nueva bandera para esto a la entidad Booking
.
En tu terminal, ejecuta:
symfony make:entity Booking
¡Uy!
symfony console make:entity Booking
¿Añadir un nuevo campo llamado reminderSentAt
, tipo datetime_immutable
, anulable? Sí. Se trata de un patrón habitual que utilizo para este tipo de campos bandera en lugar de un simple boolean
.null
significa false
y una fecha significa true
. Funciona igual, pero nos da un poco más de información.
Pulsa intro para salir del comando.
En la entidad Booking
... aquí está nuestra nueva propiedad, y aquí abajo, el getter y el setter.
Encontrar reservas para recordar
A continuación, necesitamos una forma de encontrar todas las reservas que necesitan que se les envíe un recordatorio. ¡El trabajo perfecto paraBookingRepository
! Añade un nuevo método llamado findBookingsToRemind()
, tipo de retorno: array
. Añade un docblock para mostrar que devuelve un array de objetos Reserva:
// ... lines 1 - 12 | |
class BookingRepository extends ServiceEntityRepository | |
{ | |
// ... lines 15 - 51 | |
/** | |
* @return Booking[] | |
*/ | |
public function findBookingsToRemind(): array | |
{ | |
// ... lines 57 - 65 | |
} | |
} |
Dentro, return $this->createQueryBuilder()
, alias b
. Encadena->andWhere('b.reminderSentAt IS NULL')
, ->andWhere('b.date <= :future')
,->andWhere('b.date > :now')
rellenando los marcadores de posición con->setParameter('future', new \DateTimeImmutable('+7 days'))
y->setParameter('now', new \DateTimeImmutable('now'))
. Termina con ->getQuery()->getResult()
:
// ... lines 1 - 12 | |
class BookingRepository extends ServiceEntityRepository | |
{ | |
// ... lines 15 - 54 | |
public function findBookingsToRemind(): array | |
{ | |
return $this->createQueryBuilder('b') | |
->andWhere('b.reminderSentAt IS NULL') | |
->andWhere('b.date <= :future') | |
->andWhere('b.date > :now') | |
->setParameter('future', new \DateTimeImmutable('+7 days')) | |
->setParameter('now', new \DateTimeImmutable('now')) | |
->getQuery() | |
->getResult() | |
; | |
} | |
} |
Fijación de Reservas Pendientes de Recordatorio
En AppFixtures
, aquí abajo, creamos algunas reservas falsas. Añade una que desencadene con seguridad el envío de un correo electrónico recordatorio:BookingFactory::createOne()
, dentro, 'trip' => $arrakis, 'customer' => $clark
y, ésta es la parte importante, 'date' => new \DateTimeImmutable('+6 days')
:
// ... lines 1 - 10 | |
class AppFixtures extends Fixture | |
{ | |
public function load(ObjectManager $manager): void | |
{ | |
// ... lines 15 - 87 | |
BookingFactory::createOne([ | |
'trip' => $arrakis, | |
'customer' => $clark, | |
'date' => new \DateTimeImmutable('+6 days'), | |
]); | |
} | |
} |
Claramente entre ahora y dentro de 7 días.
"Migración
Hemos realizado cambios en la estructura de nuestra base de datos. Normalmente, deberíamos crear una migración... pero, no estamos utilizando migraciones. Así que, simplemente forzaremos la actualización del esquema. En tu terminal, ejecuta:
symfony console doctrine:schema:update --force
Luego, vuelve a cargar los accesorios:
symfony console doctrine:fixture:load
Todo ha funcionado, ¡genial!
A continuación, ¡crearemos un nuevo correo electrónico recordatorio y un comando CLI para enviarlo!