我正在使用 Symfony 通知器和信使組件來異步發送 SMS 訊息(以及將來的推送和電子郵件通知)。
一切正常,但是一旦發送訊息,我想記錄有關它的資訊。
我可以通過訂閱WorkerMessageHandledEventwhich 為我提供Message物件,以及其中的包含Envelope及其所有Stamp物件來捕獲一條成功的訊息。從所有可用資訊中,我將使用名為MessageLog.
class MessengerSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
WorkerMessageHandledEvent::class => ['onHandled']
];
}
public function onHandled(WorkerMessageHandledEvent $event) {
$log = new MessageLog();
$log->setSentAt(new DateTime());
if($event->getEnvelope()->getMessage() instanceof SmsMessage) {
$log->setSubject($event->getEnvelope()->getMessage()->getSubject());
$log->setRecipient($event->getEnvelope()->getMessage()->getPhone());
}
// Do more tracking
}
}
我想做的是跟蹤“呼叫”訊息的物件。例如,如果我有一個新聞提要,并且發布一個帖子會發出一個通知,我想將每條記錄的訊息歸因于該帖子(以顯示每個帖子的受眾范圍/交付統計資訊 - 以及來自管理員 POV 審計和報告)。
我嘗試添加一個Stamp, 或其他嘗試將自定義元資料附加到訊息的方法,但是在使用捆綁包時它似乎被抽象了symfony/notifier。
以下是我用來發送通知的內容(或多或少 WIP):
class PostService {
protected NotifierInterface $notifier;
public function ___construct(NotifierInterface $notifier) {
$this->notifier = $notifier;
}
public function sendNotifications(Post $post) {
$notification = new PostNotification($post);
$recipients = [];
foreach($post->getNewsFeed()->getSubscribers() as $user) {
$recipients[] = new Recipient($user->getEmail(), $user->getMobilePhone());
}
$this->notifier->send($notification, ...$recipients);
}
}
class PostNotification extends Notification implements SmsNotificationInterface {
protected Post $post;
public function __construct(Post $post) {
parent::__construct();
$this->post = $post;
}
public function getChannels(RecipientInterface $recipient): array {
return ['sms'];
}
public function asSmsMessage(SmsRecipientInterface $recipient, string $transport = null): ?SmsMessage {
if($transport === 'sms') {
return new SmsMessage($recipient->getPhone(), $this->getPostContentAsSms());
}
return null;
}
private function getPostContentAsSms() {
return $post->getTitle()."\n\n".$post->getContent();
}
}
當這一切都完成時,這就是我在WorkerMessageHandledEvent
^ Symfony\Component\Messenger\Event\WorkerMessageHandledEvent^ {#5590
-envelope: Symfony\Component\Messenger\Envelope^ {#8022
-stamps: array:7 [
"Symfony\Component\Messenger\Stamp\BusNameStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\BusNameStamp^ {#10417
-busName: "messenger.bus.default"
}
]
"Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceivedStamp" => array:1 [
0 => Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceivedStamp^ {#10419
-id: "2031"
}
]
"Symfony\Component\Messenger\Stamp\TransportMessageIdStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\TransportMessageIdStamp^ {#10339
-id: "2031"
}
]
"Symfony\Component\Messenger\Stamp\ReceivedStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\ReceivedStamp^ {#5628
-transportName: "async"
}
]
"Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp^ {#7306}
]
"Symfony\Component\Messenger\Stamp\AckStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\AckStamp^ {#7159
-ack: Closure(Envelope $envelope, Throwable $e = null)^ {#6205
class: "Symfony\Component\Messenger\Worker"
this: Symfony\Component\Messenger\Worker {#5108 …}
use: {
$transportName: "async"
$acked: & false
}
}
}
]
"Symfony\Component\Messenger\Stamp\HandledStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\HandledStamp^ {#11445
-result: Symfony\Component\Notifier\Message\SentMessage^ {#2288
-original: Symfony\Component\Notifier\Message\NullMessage^ {#6625
-decoratedMessage: Symfony\Component\Notifier\Message\SmsMessage^ {#10348
-transport: null
-subject: ".................................................."
-phone: "0412345678"
}
}
-transport: "null"
-messageId: null
}
-handlerName: "Symfony\Component\Notifier\Messenger\MessageHandler::__invoke"
}
]
]
-message: Symfony\Component\Notifier\Message\SmsMessage^ {#10348}
}
-receiverName: "async"
}
doco 向我展示了將自己的郵票添加到信封的方法,我猜我可以使用它來附加元資料,例如我的Post物件,但這意味著我需要使用MessageBusInterface來發送通知。我不想這樣做,因為我想通過 路由訊息NotifierInterface以獲得渠道策略、短信傳輸等的所有好處。
tl;博士:WorkerMessageHandledEvent如果我使用NotifierInterface
uj5u.com熱心網友回復:
我找到了讓它作業的方法!
本質上,我們這里有兩個組件,Symfony通知器和 Symfony信使。當一起使用時,它們創建了一種將訊息發送到任意數量的端點的強大方式。
首先,我所做的是創建一個名為的介面NotificationStampsInterface和一個NotificationStamps滿足該介面的特征(通過使用介面方法存盤一個受保護的陣列來讀取/寫入它)。
class NotificationStampsInterface {
public function getStamps(): array;
public function addStamp(StampInterface $stamp);
public function removeStamp(StampInterface $stamp);
}
然后可以將此介面添加到您的自定義通知物件中,在這種情況下PostNotification,與NotificationStamps滿足介面方法的特征一起。
這里的技巧是,當通過通知器發送通知時,它最終會呼叫信使組件來發送訊息。處理這個的位是Symfony\Component\Notifier\Channel\SmsChannel. 本質上,如果 MessageBus 可用,它將通過它推送訊息,而不是直接通過通知程式。
我們可以擴展SmsChannel類以在方法中添加我們自己的邏輯notify()。
class SmsNotify extends \Symfony\Component\Notifer\Channel\SmsChannel {
public function notify(Notification $notification, RecipientInterface $recipient, string $transportName = null): void {
$message = null;
if ($notification instanceof SmsNotificationInterface) {
$message = $notification->asSmsMessage($recipient, $transportName);
}
if (null === $message) {
$message = SmsMessage::fromNotification($notification, $recipient);
}
if (null !== $transportName) {
$message->transport($transportName);
}
if (null === $this->bus) {
$this->transport->send($message);
} else {
// New logic
if($notification instanceof NotificationStampsInterface) {
$envelope = Envelope::wrap($message, $notification->getStamps());
$this->bus->dispatch($envelope);
} else {
$this->bus->dispatch($message);
}
// Old logic
// $this->bus->dispatch($message);
}
}
}
最后,我們需要通過添加以下內容來覆寫服務services.yaml
notifier.channel.sms:
class: App\Notifier\Channel\SmsChannel
arguments: ['@texter.transports', '@messenger.default_bus']
tags:
- { name: notifier.channel, channel: sms }
就是這樣!我們現在有一種方法可以將標記附加到我們的 Notification 物件,該物件將一直傳遞到WorkerMessageHandledEvent.
一個示例用途是(至少對于我的情況)
class RelatedEntityStamp implements StampInterface {
private string $className;
private int $classId;
public function __construct(object $entity) {
$this->className = get_class($entity);
$this->classId = $entity->getId();
}
/**
* @return string
*/
public function getClassName(): string {
return $this->className;
}
/**
* @return int
*/
public function getClassId(): int {
return $this->classId;
}
}
class PostService {
protected NotifierInterface $notifier;
public function ___construct(NotifierInterface $notifier) {
$this->notifier = $notifier;
}
public function sendNotifications(Post $post) {
$notification = new PostNotification($post);
$stamp = new RelatedEntityStamp($post); // Solution
$notification->addStamp($stamp); // Solution
$recipients = [];
foreach($post->getNewsFeed()->getSubscribers() as $user) {
$recipients[] = new Recipient($user->getEmail(), $user->getMobilePhone());
}
$this->notifier->send($notification, ...$recipients);
}
}
Once the message is sent, dumping the result shows that we do indeed have our stamp registered at the point where our event fires.
^ Symfony\Component\Messenger\Event\WorkerMessageHandledEvent^ {#1078
-envelope: Symfony\Component\Messenger\Envelope^ {#1103
-stamps: array:8 [
"App\Notification\Stamp\RelatedEntityStamp" => array:1 [
0 => App\Notification\Stamp\RelatedEntityStamp^ {#1062
-className: "App\Entity\Post"
-classId: 207
}
]
"Symfony\Component\Messenger\Stamp\BusNameStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\BusNameStamp^ {#1063
-busName: "messenger.bus.default"
}
]
"Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceivedStamp" => array:1 [
0 => Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceivedStamp^ {#1066
-id: "2590"
}
]
"Symfony\Component\Messenger\Stamp\TransportMessageIdStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\TransportMessageIdStamp^ {#1067
-id: "2590"
}
]
"Symfony\Component\Messenger\Stamp\ReceivedStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\ReceivedStamp^ {#1075
-transportName: "async"
}
]
"Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp^ {#1076}
]
"Symfony\Component\Messenger\Stamp\AckStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\AckStamp^ {#1077
-ack: Closure(Envelope $envelope, Throwable $e = null)^ {#1074
class: "Symfony\Component\Messenger\Worker"
this: Symfony\Component\Messenger\Worker {#632 …}
use: {
$transportName: "async"
$acked: & false
}
}
}
]
"Symfony\Component\Messenger\Stamp\HandledStamp" => array:1 [
0 => Symfony\Component\Messenger\Stamp\HandledStamp^ {#1101
-result: Symfony\Component\Notifier\Message\SentMessage^ {#1095
-original: Symfony\Component\Notifier\Message\NullMessage^ {#1091
-decoratedMessage: Symfony\Component\Notifier\Message\SmsMessage^ {#1060
-transport: null
-subject: ".................................................."
-phone: "0412345678"
}
}
-transport: "null"
-messageId: null
}
-handlerName: "Symfony\Component\Notifier\Messenger\MessageHandler::__invoke"
}
]
]
-message: Symfony\Component\Notifier\Message\SmsMessage^ {#1060}
}
-receiverName: "async"
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/448596.html
