<?php
namespace App\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpClient\HttpClient;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use App\Service\FirebaseNotificationService;
use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events\Ticket\AgentReply;
use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events\Ticket\CustomerReply;
use Webkul\UVDesk\AutomationBundle\Workflow\Events\TicketActivity;
/**
* Custom event listener to send webhook/API requests to your backend
* and Firebase push notifications when tickets are replied to.
*/
class TicketReplyWebhookSubscriber implements EventSubscriberInterface
{
private $logger;
private $httpClient;
private $params;
private $firebaseService;
public function __construct(
LoggerInterface $logger,
ParameterBagInterface $params,
FirebaseNotificationService $firebaseService
) {
$this->logger = $logger;
$this->params = $params;
$this->httpClient = HttpClient::create();
$this->firebaseService = $firebaseService;
}
public static function getSubscribedEvents()
{
return [
// UVDesk dispatches all workflow events with this name
'uvdesk.automation.workflow.execute' => 'onWorkflowEvent',
];
}
/**
* Handle workflow events - check if it's a ticket reply event
*/
public function onWorkflowEvent($event)
{
// Log that we received an event
$this->logger->debug('Webhook subscriber received workflow event', [
'event_class' => get_class($event),
]);
// Only process ticket activity events
if (!($event instanceof TicketActivity)) {
$this->logger->debug('Event is not a TicketActivity, skipping');
return;
}
// Check event type
$eventId = $event::getId();
$this->logger->debug('TicketActivity event detected', ['event_id' => $eventId]);
if ($eventId === 'uvdesk.ticket.agent_reply') {
$this->logger->info('Agent reply event detected, sending webhook and push notification');
$this->sendWebhook('agent_reply', $event);
$this->sendPushNotification($event, 'agent_reply');
} elseif ($eventId === 'uvdesk.ticket.customer_reply') {
$this->logger->info('Customer reply event detected, sending webhook');
$this->sendWebhook('customer_reply', $event);
// Optionally send notification to agent when customer replies
// $this->sendPushNotification($event, 'customer_reply');
} elseif ($eventId === 'uvdesk.ticket.collaborator_reply') {
$this->logger->info('Collaborator reply event detected, sending webhook');
$this->sendWebhook('collaborator_reply', $event);
} else {
$this->logger->debug('Event is not a reply event, skipping', ['event_id' => $eventId]);
}
}
/**
* Send webhook to your backend
*/
private function sendWebhook(string $eventType, $event)
{
// Get webhook URL from environment variable
$webhookUrl = $_ENV['WEBHOOK_BACKEND_URL'] ?? $this->params->get('env(WEBHOOK_BACKEND_URL)') ?? null;
if (empty($webhookUrl)) {
$this->logger->warning('Webhook URL not configured. Set WEBHOOK_BACKEND_URL in .env file.');
return;
}
$this->logger->info('Sending webhook', ['url' => $webhookUrl, 'event_type' => $eventType]);
try {
// Extract ticket data from event
$ticket = $event->getTicket() ?? null;
$thread = $event->getThread() ?? null;
if (!$ticket || !$thread) {
$this->logger->warning('Ticket or thread data not available in event');
return;
}
// Prepare payload to send to your backend
$payload = [
'event_type' => $eventType,
'ticket_id' => $ticket->getId(),
'ticket_number' => 'TKT-' . str_pad($ticket->getId(), 6, '0', STR_PAD_LEFT), // Format: TKT-000001
'ticket_subject' => $ticket->getSubject(),
'thread_id' => $thread->getId(),
'message' => $thread->getMessage(),
'created_by' => $thread->getCreatedBy(),
'created_at' => $thread->getCreatedAt() ? $thread->getCreatedAt()->format('Y-m-d H:i:s') : null,
'customer_email' => $ticket->getCustomer() ? $ticket->getCustomer()->getEmail() : null,
'agent_email' => $ticket->getAgent() ? $ticket->getAgent()->getEmail() : null,
];
// Send HTTP POST request to your backend
$response = $this->httpClient->request('POST', $webhookUrl, [
'json' => $payload,
'headers' => [
'Content-Type' => 'application/json',
'X-Webhook-Source' => 'uvdesk',
],
'timeout' => 10, // 10 second timeout
]);
$statusCode = $response->getStatusCode();
if ($statusCode >= 200 && $statusCode < 300) {
$this->logger->info('Webhook sent successfully', [
'event_type' => $eventType,
'ticket_id' => $ticket->getId(),
'status_code' => $statusCode,
]);
} else {
$this->logger->error('Webhook request failed', [
'event_type' => $eventType,
'ticket_id' => $ticket->getId(),
'status_code' => $statusCode,
]);
}
} catch (\Exception $e) {
$this->logger->error('Error sending webhook', [
'event_type' => $eventType,
'error' => $e->getMessage(),
]);
}
}
/**
* Send Firebase push notification to customer when agent replies
*/
private function sendPushNotification($event, string $eventType): void
{
try {
$ticket = $event->getTicket() ?? null;
$thread = $event->getThread() ?? null;
if (!$ticket || !$thread) {
return;
}
// Only send notification to customer when agent replies
if ($eventType === 'agent_reply' && $ticket->getCustomer()) {
$customerEmail = $ticket->getCustomer()->getEmail();
if (empty($customerEmail)) {
$this->logger->debug('No customer email found for push notification');
return;
}
// Prepare notification data
$ticketNumber = 'TKT-' . str_pad($ticket->getId(), 6, '0', STR_PAD_LEFT);
$title = 'New Reply on Ticket #' . $ticketNumber;
// Strip HTML tags for plain text description
$description = strip_tags(html_entity_decode($thread->getMessage()));
$description = trim($description) ?: 'You have a new reply on your ticket';
// Create Quill Delta JSON format for preview
// Format: [{"insert":"Message\n"}]
$preview = json_encode([['insert' => $description . "\n"]]);
// Additional data for deep linking
$data = [
'type' => 'ticket_reply',
'ticket_id' => (string)$ticket->getId(),
'ticket_number' => $ticketNumber,
'thread_id' => (string)$thread->getId(),
'subject' => $ticket->getSubject() ?? '',
];
// Send notification (saves to Firestore first, then sends FCM)
$this->firebaseService->sendNotificationByEmail(
$customerEmail,
$title,
$description,
$preview,
'user', // topic
$data
);
}
} catch (\Exception $e) {
$this->logger->error('Error sending push notification', [
'event_type' => $eventType,
'error' => $e->getMessage(),
]);
}
}
}