Buy Access to Course
43.

Configuración de los mensajes de un sistema externo

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

¿Qué pasaría si una cola en RabbitMQ estuviera llena de mensajes que se originan en un sistema externo... pero quisiéramos consumirlos y manejarlos desde nuestra aplicación Symfony? Por ejemplo, tal vez un usuario pueda solicitar que se elimine una foto desde un sistema totalmente diferente... y ese sistema necesita comunicarse con nuestra aplicación para que pueda realizar el borrado ¿Cómo funcionaría eso?

Cada transporte en Messenger tiene realmente dos funciones: una, enviar mensajes a un corredor de mensajes o sistema de colas y dos, recibir mensajes de ese mismo sistema y gestionarlos.

Y, como hablamos en el último vídeo, no es necesario que utilices ambas funciones de un transporte: puedes elegir enviar a un transporte, pero no leer ni consumir nunca esos mensajes... porque lo hará otro sistema. O puedes hacer lo contrario: crear un transporte al que nunca enviarás, pero que utilizarás para consumir mensajes... que probablemente fueron puestos ahí por algún sistema externo. El truco para hacer esto es crear un serializador que pueda entender el formato de esos mensajes externos.

Crear un nuevo Mensaje y Manejador

En lugar de sobreexplicar esto, veámoslo en acción. En primer lugar, imagina que este sistema externo imaginario necesita poder decirle a nuestra aplicación que haga algo... muy... importante: registrar un Emoji. Vale, puede que no sea el tipo de mensaje más impresionante... pero los detalles de lo que este mensaje externo le dice a nuestra aplicación que haga no son importantes: podría decirnos que subamos una imagen con detalles sobre la ubicación del archivo, que eliminemos una imagen, que enviemos un correo electrónico a un usuario registrado o que registremos un emoji

Pongamos esto en marcha. Normalmente, si quisiéramos enviar un comando para registrar un emoji, empezaríamos por crear una clase de mensaje y un manejador de mensajes. En este caso... haremos exactamente lo mismo. En el directorio Command/, crea una nueva clase PHP llamada LogEmoji

19 lines | src/Message/Command/LogEmoji.php
// ... lines 1 - 2
namespace App\Message\Command;
class LogEmoji
{
// ... lines 7 - 17
}

Añade un argumento public function __construct(). Para indicarnos qué emoji debemos registrar, el sistema exterior nos enviará un índice entero del emoji que quieren - nuestra aplicación tendrá una lista de emojis. Así que añade un argumento $emojiIndex y luego pulsa Alt+Enter y selecciona "Inicializar campos" para crear esa propiedad y establecerla.

19 lines | src/Message/Command/LogEmoji.php
// ... lines 1 - 2
namespace App\Message\Command;
class LogEmoji
{
private $emojiIndex;
public function __construct(int $emojiIndex)
{
$this->emojiIndex = $emojiIndex;
}
// ... lines 13 - 17
}

Para hacer que esta propiedad sea legible por el manejador, ve al menú Código -> Generar -o Comando + N en un Mac-, selecciona getters y genera getEmojiIndex().

19 lines | src/Message/Command/LogEmoji.php
// ... lines 1 - 2
namespace App\Message\Command;
class LogEmoji
{
private $emojiIndex;
public function __construct(int $emojiIndex)
{
$this->emojiIndex = $emojiIndex;
}
public function getEmojiIndex(): int
{
return $this->emojiIndex;
}
}

¡Genial! Una clase de mensaje perfectamente aburrida y normal. Segundo paso: en el directorioMessageHandler/Command/, crea una nueva clase LogEmojiHandler. Haz que implemente nuestra clase normal MessageHandlerInterface y añadepublic function __invoke() con el tipo de mensaje: LogEmoji $logEmoji.

// ... lines 1 - 2
namespace App\MessageHandler\Command;
use App\Message\Command\LogEmoji;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class LogEmojiHandler implements MessageHandlerInterface
{
public function __invoke(LogEmoji $logEmoji)
{
}
}

Ahora... ¡nos ponemos a trabajar! Voy a pegar una lista de emojis en la parte superior: aquí están los cinco que el sistema exterior puede elegir: galleta, dinosaurio, queso, robot y, por supuesto, caca

// ... lines 1 - 8
class LogEmojiHandler implements MessageHandlerInterface
{
private static $emojis = [
'?',
'?',
'?',
'?',
'?'
];
// ... lines 18 - 33
}

Y luego, como vamos a registrar algo, añade un método __construct()con la pista de tipo LoggerInterface. Pulsa Alt + Intro y selecciona "Inicializar campos" una vez más para crear esa propiedad y establecerla.

// ... lines 1 - 5
use Psr\Log\LoggerInterface;
// ... lines 7 - 8
class LogEmojiHandler implements MessageHandlerInterface
{
private static $emojis = [
'?',
'?',
'?',
'?',
'?'
];
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
// ... lines 25 - 33
}

Dentro de __invoke(), nuestro trabajo es bastante sencillo. Para obtener el emoji, establece una variable$index en $logEmoji->getEmojiIndex()

// ... lines 1 - 5
use Psr\Log\LoggerInterface;
// ... lines 7 - 8
class LogEmojiHandler implements MessageHandlerInterface
{
private static $emojis = [
'?',
'?',
'?',
'?',
'?'
];
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function __invoke(LogEmoji $logEmoji)
{
$index = $logEmoji->getEmojiIndex();
// ... lines 30 - 32
}
}

Luego $emoji = self::$emojis - para referenciar esa propiedad estática -self::$emojis[$index] ?? self::emojis[0].

// ... lines 1 - 5
use Psr\Log\LoggerInterface;
// ... lines 7 - 8
class LogEmojiHandler implements MessageHandlerInterface
{
private static $emojis = [
'?',
'?',
'?',
'?',
'?'
];
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function __invoke(LogEmoji $logEmoji)
{
$index = $logEmoji->getEmojiIndex();
$emoji = self::$emojis[$index] ?? self::$emojis[0];
// ... lines 31 - 32
}
}

En otras palabras, si el índice existe, úsalo. Si no, vuelve a registrar una cookie... porque... a todo el mundo le gustan las cookies. Registra con$this->logger->info('Important message! ')y luego con $emoji.

// ... lines 1 - 5
use Psr\Log\LoggerInterface;
// ... lines 7 - 8
class LogEmojiHandler implements MessageHandlerInterface
{
private static $emojis = [
'?',
'?',
'?',
'?',
'?'
];
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function __invoke(LogEmoji $logEmoji)
{
$index = $logEmoji->getEmojiIndex();
$emoji = self::$emojis[$index] ?? self::$emojis[0];
$this->logger->info('Important message! '.$emoji);
}
}

La gran conclusión de este nuevo gestor de mensajes y mensajes es que, bueno, ¡no se diferencia en absoluto de cualquier otro gestor de mensajes y mensajes! A Messenger no le importa si el objeto LogEmoji se enviará manualmente desde nuestra propia aplicación o si un trabajador recibirá un mensaje de un sistema externo que se asignará a esta clase.

Para probarlo, sube a ImagePostController, busca el método create() y, sólo para asegurarte de que esto funciona, añade:$messageBus->dispatch(new LogEmoji(2)).

107 lines | src/Controller/ImagePostController.php
// ... lines 1 - 7
use App\Message\Command\LogEmoji;
// ... lines 9 - 25
class ImagePostController extends AbstractController
{
// ... lines 28 - 42
public function create(Request $request, ValidatorInterface $validator, PhotoFileManager $photoManager, EntityManagerInterface $entityManager, MessageBusInterface $messageBus)
{
// ... lines 45 - 73
$messageBus->dispatch(new LogEmoji(2));
// ... lines 75 - 76
}
// ... lines 78 - 105
}

Si esto funciona, deberíamos ver un mensaje en nuestros registros cada vez que subamos una foto. Busca tu terminal: veamos los logs con:

tail -f var/log/dev.log

Este es el archivo de registro del entorno dev. Despejaré mi pantalla, luego me desplazaré, seleccionaré una foto y... retrocederé. Ahí está:

¡Mensaje importante! 🧀

¡Estoy de acuerdo! ¡Eso es importante! Esto es genial... pero no es lo que realmente queremos. Lo que realmente queremos es utilizar un trabajador para consumir un mensaje de una cola -probablemente un mensaje JSON- y transformarlo de forma inteligente en un objeto LogEmoji para que Messenger pueda manejarlo. ¿Cómo lo hacemos? Con un transporte dedicado y un serializador de clientes. ¡Hagamos eso a continuación!