<?php
namespace App\EventSubscriber;
use ApiPlatform\Symfony\EventListener\EventPriorities;
use App\Entity\Customer;
use App\Service\Geocoding;
use App\Service\Twilio;
use JetBrains\PhpStorm\ArrayShape;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use function get_class;
use function in_array;
use function method_exists;
final class LocationUpdatedSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly Geocoding $geocoding,
private readonly Twilio $twilio,
)
{
}
#[ArrayShape([KernelEvents::VIEW => "array"])]
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => ['checkLocation', EventPriorities::POST_WRITE],
];
}
public function checkLocation(ViewEvent $event): void
{
$entity = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!in_array($method, ['POST', 'PUT', 'PATCH'])) {
return;
}
# at the time of writing, this is just Pond or Employee but could expand in the future and this caters for that
if (method_exists($entity, 'getLatitude') && method_exists($entity, 'getLongitude')) {
$this->setCoordinates($entity);
return;
}
# when a customer is posted, it contains ponds
if ($entity instanceof Customer) {
foreach ($entity->getPonds() as $pond) {
$this->setCoordinates($pond);
}
}
}
private function setCoordinates($entity): void
{
$result = $this->geocoding->updateEntityLngLat($entity);
# if the Google API didn't give us coordinates then notify We Do Code to investigate
if (!$result) {
$entityClass = get_class($entity);
$address = method_exists($entity, 'getAddressAsString') ? $entity->getAddressAsString() : '';
$content = <<<TEXT
We failed to get coordinates for $entityClass entity {$entity->getId()}.
The address is: $address
TEXT;
$this->twilio->email(
toAddress: '[email protected]',
toName: 'We Do Code',
content: $content,
subject: '[PNW] Failed to get coordinates',
format: true,
);
}
}
}