src/EventSubscriber/JobIncompleteSubscriber.php line 46

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use ApiPlatform\Symfony\EventListener\EventPriorities;
  4. use App\Entity\Job;
  5. use App\Entity\Schedule;
  6. use App\Entity\User;
  7. use App\Service\Message;
  8. use Doctrine\Persistence\ManagerRegistry;
  9. use JetBrains\PhpStorm\ArrayShape;
  10. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpKernel\Event\ViewEvent;
  13. use Symfony\Component\HttpKernel\KernelEvents;
  14. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  15. use function array_multisort;
  16. use function current;
  17. use function in_array;
  18. final class JobIncompleteSubscriber implements EventSubscriberInterface
  19. {
  20.     /** @var string The relative path inside templates/messages without any extensions */
  21.     private const TEMPLATE 'job/incomplete';
  22.     /** @var int The user ID of the admin user to notify */
  23.     private const ADMIN_TO_NOTIFY 1;
  24.     public function __construct(
  25.         private readonly TokenStorageInterface $tokenStorage,
  26.         private readonly ManagerRegistry $managerRegistry,
  27.         private readonly Message $messageService,
  28.     )
  29.     {
  30.     }
  31.     #[ArrayShape([KernelEvents::VIEW => "array"])]
  32.     public static function getSubscribedEvents(): array
  33.     {
  34.         return [
  35.             KernelEvents::VIEW => ['sendMessage'EventPriorities::POST_WRITE],
  36.         ];
  37.     }
  38.     public function sendMessage(ViewEvent $event): void
  39.     {
  40.         $job $event->getControllerResult();
  41.         $method $event->getRequest()->getMethod();
  42.         # PUT and PATCH methods are used to update instances, and we are only interested in updated jobs
  43.         if (!$job instanceof Job || !in_array($method, [Request::METHOD_PUTRequest::METHOD_PATCH])) {
  44.             return;
  45.         }
  46.         $previousData $event->getRequest()->get('previous_data');
  47.         # If the status hasn't changed, we're not interested
  48.         if ($previousData->getStatus() === $job->getStatus()) {
  49.             return;
  50.         }
  51.         # If the status hasn't changed to "unable to complete", we're not interested
  52.         if ($job->getStatus() !== Job::JOB_STATUS_UNABLE_TO_COMPLETE) {
  53.             return;
  54.         }
  55.         // @todo find a better way of choosing which admin(s) to notify
  56.         $admin $this->managerRegistry->getRepository(User::class)
  57.             ->find(self::ADMIN_TO_NOTIFY);
  58.         /** @var User $currentUser */
  59.         $currentUser $this->tokenStorage->getToken()->getUser();
  60.         $schedule $this->getLatestSchedule($job);
  61.         $message $this->messageService
  62.             ->withRecipient($admin)
  63.             ->withSubject('A job was marked as incomplete')
  64.             ->withTemplate(self::TEMPLATE)
  65.             ->withTemplateData([
  66.                 'employeeName' => $currentUser->getFirstName(),
  67.                 'addressLine1' => $job->getPond()->getAddress1(),
  68.                 'customerName' => $job->getPond()->getCustomer()->getFirstName(),
  69.                 'fullAddress' => $job->getPond()->getAddress(),
  70.                 'reason' => $this->getReasonText($schedule),
  71.                 'notes' => $schedule->getNotes(),
  72.             ]);
  73.         if ($currentUser instanceof User) {
  74.             $message $message->withCurrentUser($currentUser);
  75.         }
  76.         $message->send();
  77.     }
  78.     private function getLatestSchedule(Job $job): Schedule
  79.     {
  80.         /** @var iterable<int, Schedule> $schedules */
  81.         $schedules $this->managerRegistry->getRepository(Schedule::class)
  82.             ->findBy(['job' => $job]);
  83.         $sort = [];
  84.         foreach ($schedules as $schedule) {
  85.             $sort[] = $schedule->getDate()->getTimestamp();
  86.         }
  87.         array_multisort($schedulesSORT_DESC$sort);
  88.         return current($schedules);
  89.     }
  90.     private function getReasonText(Schedule $schedule): string|bool
  91.     {
  92.         return match($schedule->getIncompleteReason()) {
  93.             Schedule::INCOMPLETE_REASON_TIME => 'we ran out of time',
  94.             Schedule::INCOMPLETE_REASON_MATERIALS => 'we had an issue with materials',
  95.             Schedule::INCOMPLETE_REASON_NO_ACCESS => 'we had issues with accessing the pond',
  96.             default => false// we will handle "other" in the template
  97.         };
  98.     }
  99. }