확장에서 회원에게 알림을 보내는 방법입니다. 세 갈래(내부 알림·푸시·외부 발송)가 있고, 필요한 것만 골라 씁니다.
내부 알림 (종 아이콘) — 항상 사용 가능
코어가 늘 제공하므로 MemberNotificationPublisherInterface 를 생성자로 주입받아 씁니다.
use Mublo\Contract\Notification\MemberNotificationPublisherInterface;
use Mublo\Contract\Notification\MemberNotification;
class OrderService
{
public function __construct(
private MemberNotificationPublisherInterface $notifier,
) {}
public function notifyShipped(int $domainId, int $memberId, int $orderId): void
{
$this->notifier->publish(new MemberNotification(
domainId: $domainId,
memberId: $memberId,
type: 'order_shipped',
title: '상품이 발송되었습니다',
body: '주문하신 상품이 오늘 출고됐어요.',
targetUrl: '/mypage/orders/' . $orderId,
source: 'plugin',
deduplicationKey: 'ship:' . $orderId,
));
}
}
deduplicationKey 를 주면 같은 키로는 한 번만 저장돼, 이벤트가 두 번 돌아도 알림이 겹치지 않습니다.
푸시 (앱·브라우저) — 있을 때만
푸시 전송 기능은 별도 확장이 제공합니다. 설치돼 있지 않을 수 있으니, 계약이 있는지 확인하고 씁니다.
use Mublo\Core\Registry\ContractRegistry;
use Mublo\Contract\Fcm\FcmMessageServiceInterface;
// $registry 는 ContractRegistry (생성자로 주입)
if ($registry->has(FcmMessageServiceInterface::class)) {
$push = $registry->resolve(FcmMessageServiceInterface::class);
$push->dispatchToMember(
domainId: $domainId,
memberId: $memberId,
installationType: null, // null = 웹·안드로이드·iOS 전체
action: 'order_shipped',
payload: ['orderId' => $orderId],
);
}
반환값 Result 에 ['sent' => N, 'failed' => N] 이 담깁니다. 푸시가 필수가 아니라면 has() 로 감싸 없어도 동작하게 하세요.
외부 발송 (문자·이메일) — 있을 때만
use Mublo\Contract\Notification\NotificationGatewayInterface;
if ($registry->has(NotificationGatewayInterface::class)) {
$gateway = $registry->resolve(NotificationGatewayInterface::class);
$gateway->send(
channel: 'sms',
templateCode: 'order_shipped',
recipient: $phone,
fieldValues: ['orderer_name' => $name],
);
}
내가 전송 백엔드를 제공하려면
반대로 실제 전송을 담당하는 확장을 만든다면, 계약을 구현하고 등록합니다.
class MyPushService implements FcmMessageServiceInterface
{
// dispatchToInstallation() / dispatchToMember() / dispatchToTopic() 구현
}
// Provider boot
$registry->bind(FcmMessageServiceInterface::class, new MyPushService());
이제 다른 확장이 has() 로 확인하면 참이 되고, 위 소비자 코드가 그대로 동작합니다. 계약이 소비자와 제공자를 느슨하게 이어 줍니다.