<?php
/**
* This file is part of the AURES Frontend API package.
*
* (c) AURES HOLDING <info@aaaauto.cz>
*
*/
namespace App\EventListener;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\Mime\Email;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mime\Address;
use App\Exception\CommandException;
use Exception;
use Throwable;
/**
* Analize all bundle exception and fire propper actions.
*
* @author David Evdoshchenko <4341922@gmail.com>
*/
class ExceptionListener
{
/**
* These credit will be used if you set it to non-empty.
* Otherwise will be used recepients from App services config.
*
* FROM:
* fill with (single) if you need custom 'from' for this command:
* - 'email' => 'your@mail.com',
* - 'name' => 'Your Name'
*
* TO:
* fill with (multiple) if you need custom 'to' for this command:
* - ['email' => 'your@mail.com', 'name' => 'Your Name']
*
* @var array
*/
private array $mailRecepientsDefault = [
'from' => [],
'to' => [],
];
/**
* These cred will be used if none provided.
*
* @var MailerInterface
*/
private MailerInterface $mailer;
/**
* These cred will be used if none provided.
*
* @var array
*/
private array $mailRecepients;
/**
* Constructor
*
* @param MailerInterface $mailer Symfony mailer.
* @param array $mailRecepients Emails and Names.
*
* @return void
*/
public function __construct(MailerInterface $mailer, array $mailRecepients)
{
$this->mailer = $mailer;
$this->mailRecepients = $mailRecepients;
}
/**
* Event handler
*
* @param ConsoleErrorEvent $event Event itself.
*
* @return void
*/
public function onConsoleError(ConsoleErrorEvent $event): void
{
$exception = $event->getError();
$command = $event->getCommand();
if ($exception instanceof CommandException) {
$this->notifyCommandException($exception, $command);
}
}
/**
* Prepare email msg and send it.
*
* @param Throwable $e Exception
* @param Command $command Command
*
* @return void
*/
private function notifyCommandException(Throwable $e, Command $command): void
{
$cloner = new VarCloner();
$dumper = new HtmlDumper();
$class = $command::class;
$name = $command->getDefaultName();
$dump = $dumper->dump($cloner->cloneVar($e), true);
if (property_exists($command, 'mailRecepients')) {
$recepients = $command->mailRecepients;
} else {
$recepients = $this->mailRecepientsDefault;
$e = new Exception("Command {$name} within class {$class} thrown exception, but it does not realize property mailRecepients, fallback to default ones", $e->getCode(), $e);
}
$this->resolveRecipients($recepients);
$email = (new TemplatedEmail())
->from($recepients['from'])
->to(...$recepients['to'])
->priority(Email::PRIORITY_HIGH)
->subject('Runtime Exception!')
->htmlTemplate('emails/error-log-exception.html.twig')
->context([
'command' => $name,
'exception' => $e,
'dump' => $dump,
]);
$this->sendMail($email);
}
/**
* Set default recipients if none provided.
*
* @param array $recipients To and From.
*
* @return void
*/
private function resolveRecipients(array &$recipients): void
{
// This ones comes from service.yaml by DI.
$defaults = $this->mailRecepients['exception'];
if (empty($recipients['from'])) {
$recipients['from'] = new Address($defaults['from']['mail'], $defaults['from']['name']);
}
if (empty($recipients['to'])) {
$recipients['to'] = array_map(fn($recipient) => new Address($recipient['mail'], $recipient['name']), $defaults['to']);
}
}
/**
* Transport.
*
* @param Email $mail Mail instance.
*/
private function sendMail(Email $mail): void
{
$this->mailer->send($mail);
}
}