<?php
namespace AdminBundle\Services;
use AdminBundle\Entity\Booking;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
/**
* Webhook Service - Trimite evenimente booking către Zendesk Bridge
*
* INSTALARE: Copy-paste acest fișier în src/AdminBundle/Services/
*/
class WebhookService
{
private $webhookUrl;
private $webhookSecret;
private $logger;
private $enabled;
public function __construct(
string $webhookUrl,
string $webhookSecret,
bool $enabled = true,
LoggerInterface $logger = null
) {
$this->webhookUrl = $webhookUrl;
$this->webhookSecret = $webhookSecret;
$this->enabled = $enabled;
$this->logger = $logger ?: new NullLogger();
}
/**
* Trimite webhook pentru un eveniment booking
*/
public function send(Booking $booking, string $event): bool
{
if (!$this->enabled) {
return true;
}
$payload = $this->buildPayload($booking, $event);
$jsonPayload = json_encode($payload);
$signature = $this->generateSignature($jsonPayload);
try {
$ch = curl_init($this->webhookUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $jsonPayload,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Webhook-Signature: ' . $signature,
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($httpCode === 200) {
$this->logger->info('Webhook sent', [
'booking' => $booking->getKey(),
'event' => $event,
]);
return true;
}
$this->logger->error('Webhook failed', [
'booking' => $booking->getKey(),
'event' => $event,
'httpCode' => $httpCode,
'error' => $error,
'response' => $response,
]);
return false;
} catch (\Exception $e) {
$this->logger->error('Webhook exception', [
'booking' => $booking->getKey(),
'event' => $event,
'exception' => $e->getMessage(),
]);
return false;
}
}
/**
* Construiește payload-ul webhook cu toate datele necesare
*/
private function buildPayload(Booking $booking, string $event): array
{
$payload = [
'key' => $booking->getKey(),
'event' => $event,
'data' => [
'booking' => [
'client_name' => trim($booking->getClientFirstName() . ' ' . $booking->getClientLastName()),
'client_email' => $booking->getClientEmail(),
'client_phone' => $booking->getClientPhone(),
'pickup_address' => $booking->getPickUpAddress(),
'pickup_datetime' => $booking->getPickUpDateTime()
? $booking->getPickUpDateTime()->format('c')
: null,
'destination' => $booking->getDestinationAddress(),
'flight_number' => $booking->getFlightNumber(),
'notes' => $booking->getNotes(),
'price' => $booking->getOverridePrice(),
'payment_type' => $this->getPaymentTypeName($booking->getPaymentType()),
],
],
];
// Adaugă date șofer dacă e alocat
$driver = $booking->getDriver();
if ($driver) {
$payload['data']['driver'] = [
'id' => $driver->getId(),
'name' => $driver->getInternalName() ?: $driver->getFullName(),
'phone' => $driver->getPhone() ?: $driver->getMobilePhone(),
];
$car = $driver->getCar();
if ($car) {
$payload['data']['driver']['vehicle'] = trim($car->getMaker() . ' ' . $car->getModel());
$payload['data']['driver']['registration'] = $car->getPlateNumber();
}
}
return $payload;
}
/**
* Generează semnătura HMAC-SHA256
*/
private function generateSignature(string $payload): string
{
$timestamp = time();
$signedPayload = $timestamp . '.' . $payload;
$signature = hash_hmac('sha256', $signedPayload, $this->webhookSecret);
return "t={$timestamp},v1={$signature}";
}
/**
* Convertește tipul de plată în nume
*/
private function getPaymentTypeName(?int $type): string
{
$types = [
1 => 'Cash',
2 => 'Card',
3 => 'Account',
4 => 'Invoice',
];
return $types[$type] ?? 'Unknown';
}
// =========================================
// METODE HELPER - APELEAZĂ DIN EVENT LISTENER
// =========================================
public function onDispatched(Booking $booking): bool
{
return $this->send($booking, 'dispatched');
}
public function onAccepted(Booking $booking): bool
{
return $this->send($booking, 'accepted');
}
public function onEnroute(Booking $booking): bool
{
return $this->send($booking, 'enroute');
}
public function onArrived(Booking $booking): bool
{
return $this->send($booking, 'arrived');
}
public function onStarted(Booking $booking): bool
{
return $this->send($booking, 'started');
}
public function onCompleted(Booking $booking): bool
{
return $this->send($booking, 'completed');
}
public function onCancelled(Booking $booking): bool
{
return $this->send($booking, 'cancelled');
}
public function onNoShow(Booking $booking): bool
{
return $this->send($booking, 'no_show');
}
}