Organización del bus de eventos y comandos
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeYa hemos organizado nuestra nueva clase de eventos en un subdirectorio Event
. ¡Genial! Hagamos lo mismo con nuestros comandos. Crea un nuevo subdirectorio Command/
, mueve las dos clases de comandos dentro... y añade \Command
al final del espacio de nombres de ambas clases.
Veamos... ahora que hemos cambiado esos espacios de nombres... tenemos que actualizar algunas cosas. Empieza en messenger.yaml
: estamos haciendo referencia a AddPonkaToImage
. Añade Command
a ese nombre de clase. A continuación, en ImagePostController
, arriba del todo, estamos haciendo referencia a los dos comandos. Actualiza el espacio de nombres en cada uno de ellos.
Y por último, en los manejadores, tenemos lo mismo: cada manejador tiene una declaración use
para la clase de comando que maneja. Añade el espacio de nombres Command\
en ambos.
¡Genial! Hagamos lo mismo con los manejadores: crea un nuevo subdirectorio llamado Command/
, muévelos dentro... y añade el espacio de nombres \Command
a cada uno. Eso es... todo lo que tenemos que cambiar.
¡Me gusta! Este cambio no tiene nada de técnico... sólo es una buena forma de organizar las cosas si piensas utilizar algo más que comandos, es decir, eventos o mensajes de consulta. Y todo funcionará exactamente igual que antes. Para comprobarlo, en tu terminal, ejecuta debug:messenger
:
php bin/console debug:messenger
¡Sí! Vemos la misma información que antes.
Vinculación de los manejadores a un bus
Pero... ahora que hemos separado nuestros manejadores de eventos de nuestros manejadores de comandos... podemos hacer algo especial: podemos vincular cada manejador al bus específico al que está destinado. De nuevo, no es superimportante hacer esto, pero hará que las cosas estén más claras.
Te lo mostraré: abre config/services.yaml
. Esta línea App\
es la responsable de registrar automáticamente cada clase del directorio src/
como un servicio en el contenedor.
La línea siguiente repite eso para las clases del directorio Controller/
. ¿Por qué? Esto anulará los servicios del controlador registrados anteriormente y añadirá una etiqueta especial que los controladores necesitan para funcionar.
Podemos utilizar un truco similar con Messenger. Digamos App\MessageHandler\Command\
, y luego utilizar la tecla resource
para volver a registrar todas las clases del directorio ../src/MessageHandler/Command
. Uy, me he equivocado con el nombre del directorio... Veré un gran error en unos minutos... y lo arreglaré.
// ... lines 1 - 7 | |
services: | |
// ... lines 9 - 29 | |
App\MessageHandler\Command\: | |
resource: '../src/MessageHandler/Command' | |
// ... lines 32 - 44 |
Si sólo hiciéramos esto... no cambiaría absolutamente nada. Esto registraría todo lo que hay en este directorio como un servicio... pero eso ya lo hace la primera entrada de App\
de todos modos.
Pero ahora podemos añadir una etiqueta a esto con name: messenger.message_handler
y bus:
configurada con... el nombre de mi bus de messenger.yaml
. Copia messenger.bus.default
y di bus: messenger.bus.default
.
// ... lines 1 - 7 | |
services: | |
// ... lines 9 - 29 | |
App\MessageHandler\Command\: | |
resource: '../src/MessageHandler/Command' | |
// ... line 32 | |
tags: [{ name: messenger.message_handler, bus: messenger.bus.default }] | |
// ... lines 34 - 44 |
Aquí ocurren varias cosas. Primero, cuando Symfony ve una clase en nuestro código que implementa MessageHandlerInterface
, añade automáticamente esta etiqueta messenger.message_handler
. Así es como Messenger sabe qué clases son manejadoras de mensajes.
Ahora estamos añadiendo esa etiqueta manualmente para poder decir también exactamente en qué bus se debe utilizar este manejador. Sin la opción bus
, se añade a todos los buses.
También tenemos que añadir una clave más: autoconfigure: false
.
// ... lines 1 - 7 | |
services: | |
// ... lines 9 - 29 | |
App\MessageHandler\Command\: | |
resource: '../src/MessageHandler/Command' | |
autoconfigure: false | |
tags: [{ name: messenger.message_handler, bus: messenger.bus.default }] | |
// ... lines 34 - 44 |
Gracias a la sección _defaults
de la parte superior, todos los servicios de nuestro directorio src/
tendrán, por defecto, activada la opción autoconfigure
... que es la responsable de añadir automáticamente la etiqueta messenger.message_handler
a todos los servicios que implementen MessageHandlerInterface
. La desactivamos para los servicios de este directorio para que la etiqueta no se añada dos veces.
¡Ufff! Puedes ver el resultado final ejecutando de nuevo debug:messenger
.
php bin/console debug:messenger
¡Oh, el resultado final es un gran error gracias a mi errata! Asegúrate de que estás haciendo referencia al directorio MessageHandler
. Prueba de nuevo con debug:messenger
:
php bin/console debug:messenger
¡Bien! El bus de eventos ya no dice que podamos enviar los dos comandos. Lo que realmente significa es que los manejadores de comandos se añadieron al bus de comandos, pero no al bus de eventos.
Repitamos esto para los eventos: copia esta sección, pégala, cambia el espacio de nombres a Event\
, el directorio a Event
y actualiza la opción bus
aevent.bus
-el nombre de nuestro otro bus dentro de messenger.yaml
.
// ... lines 1 - 7 | |
services: | |
// ... lines 9 - 34 | |
App\MessageHandler\Event\: | |
resource: '../src/MessageHandler/Event' | |
autoconfigure: false | |
tags: [{ name: messenger.message_handler, bus: event.bus }] | |
// ... lines 39 - 44 |
¡Genial! Prueba de nuevo con debug:messenger
:
php bin/console debug:messenger
¡Perfecto! Nuestros dos manejadores de comandos están vinculados al bus de comandos y nuestro único manejador de eventos está vinculado al bus de eventos.
Una vez más, hacer este último paso no era tan importante... pero me gustan mucho estos subdirectorios... y ajustar las cosas es agradable.
Cambiar el nombre del bus de comandos
Ah, pero mientras limpiamos las cosas, de vuelta en config/packages/messenger.yaml
, nuestro bus principal se llama messenger.bus.default
, que se convierte en el id de servicio del bus en el contenedor. Usamos este nombre... sólo porque ese es el valor por defecto que usa Symfony cuando sólo tienes un bus. Pero como este es un bus de comandos, ¡llamémoslo así! Cámbiale el nombre a command.bus
. Y arriba, utiliza eso como nuestro default_bus
.
framework: | |
messenger: | |
default_bus: command.bus | |
buses: | |
command.bus: | |
// ... lines 7 - 35 |
¿Dónde estaba la antigua clave referenciada en nuestro código? Gracias a que autoconducimos ese servicio a través de su tipo-indicación... casi en ningún sitio: sólo en services.yaml
. Cambia también la opción del bus a command.bus
.
// ... lines 1 - 7 | |
services: | |
// ... lines 9 - 29 | |
App\MessageHandler\Command\: | |
// ... lines 31 - 32 | |
tags: [{ name: messenger.message_handler, bus: command.bus }] | |
// ... lines 34 - 44 |
Comprueba todo ejecutando debug:messenger
una vez más:
php bin/console debug:messenger
Qué bien: dos buses, cada uno con un gran nombre y que sólo conocen los manejadores correctos.
Ah, y este AuditMiddleware
es algo que realmente deberíamos utilizar también en event.bus
: registra el recorrido de los mensajes... lo que es igualmente válido aquí.
framework: | |
messenger: | |
// ... lines 3 - 4 | |
buses: | |
// ... lines 6 - 9 | |
event.bus: | |
// ... line 11 | |
middleware: | |
- App\Messenger\AuditMiddleware | |
// ... lines 14 - 37 |
Si te gusta esta organización, ¡genial! Si te parece demasiado, no te compliques: Messenger está aquí para hacer lo que tú quieras. A continuación, vamos a hablar del último tipo de bus de mensajes: el bus de consulta.
We are using two bus for command and event; let you have an Handler who react to an Event. This handler has to perform an action that usually is handled by a Command but after it has to dispatch an Event.
Example: we have a microservices who send SMS. There is a main command "SendSMSCommand"
Another MS need to send an SMS when dispatching an Event. This Event is catched from SMS with a dedicated Handler, who has to inject: eventBus AND commandBus, cause it has to use CommandBus to handle the sending of SMS, and eventBus to throw an new SmsSentEvent. Is it correct? To use two buses in an EventHandler?