143 lines
6.2 KiB
PHP

<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocGeneratorBundle\Service\Messenger;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
use Chill\DocGeneratorBundle\Service\Generator\GeneratorException;
use Chill\DocGeneratorBundle\Service\Generator\GeneratorInterface;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Exception\StoredObjectManagerException;
use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Handle the request of document generation.
*/
class RequestGenerationHandler implements MessageHandlerInterface
{
final public const AUTHORIZED_TRIALS = 5;
private const LOG_PREFIX = '[docgen message handler] ';
public function __construct(
private readonly DocGeneratorTemplateRepositoryInterface $docGeneratorTemplateRepository,
private readonly EntityManagerInterface $entityManager,
private readonly GeneratorInterface $generator,
private readonly LoggerInterface $logger,
private readonly StoredObjectRepositoryInterface $storedObjectRepository,
private readonly UserRepositoryInterface $userRepository,
private readonly MailerInterface $mailer,
private readonly TranslatorInterface $translator,
private readonly StoredObjectManagerInterface $storedObjectManager,
) {}
public function __invoke(RequestGenerationMessage $message)
{
if (null === $template = $this->docGeneratorTemplateRepository->find($message->getTemplateId())) {
throw new \RuntimeException('template not found: '.$message->getTemplateId());
}
if (null === $destinationStoredObject = $this->storedObjectRepository->find($message->getDestinationStoredObjectId())) {
throw new \RuntimeException('destination stored object not found : '.$message->getDestinationStoredObjectId());
}
if ($destinationStoredObject->getGenerationTrialsCounter() >= self::AUTHORIZED_TRIALS) {
$this->logger->error(self::LOG_PREFIX.'Request generation abandoned: maximum number of retry reached', [
'template_id' => $message->getTemplateId(),
'destination_stored_object' => $message->getDestinationStoredObjectId(),
'trial' => $destinationStoredObject->getGenerationTrialsCounter(),
]);
throw new UnrecoverableMessageHandlingException('maximum number of retry reached');
}
$creator = $this->userRepository->find($message->getCreatorId());
// we increase the number of generation trial in the object, and, in the same time, update the counter
// on the database side. This ensure that, if the script fails for any reason (memory limit reached), the
// counter is inscreased
$destinationStoredObject->addGenerationTrial();
$this->entityManager->createQuery('UPDATE '.StoredObject::class.' s SET s.generationTrialsCounter = s.generationTrialsCounter + 1 WHERE s.id = :id')
->setParameter('id', $destinationStoredObject->getId())
->execute();
try {
if ($message->isDumpOnly()) {
$destinationStoredObject = $this->generator->generateDataDump(
$template,
$message->getEntityId(),
$message->getContextGenerationData(),
$destinationStoredObject,
$creator
);
$this->sendDataDump($destinationStoredObject, $message);
} else {
$this->generator->generateDocFromTemplate(
$template,
$message->getEntityId(),
$message->getContextGenerationData(),
$destinationStoredObject,
$creator
);
}
} catch (StoredObjectManagerException|GeneratorException $e) {
$this->entityManager->flush();
$this->logger->error(self::LOG_PREFIX.'Request generation failed', [
'template_id' => $message->getTemplateId(),
'destination_stored_object' => $message->getDestinationStoredObjectId(),
'trial' => $destinationStoredObject->getGenerationTrialsCounter(),
'error' => $e->getTraceAsString(),
]);
throw $e;
}
$this->entityManager->flush();
$this->logger->info(self::LOG_PREFIX.'Request generation finished', [
'template_id' => $message->getTemplateId(),
'destination_stored_object' => $message->getDestinationStoredObjectId(),
'duration_int' => (new \DateTimeImmutable('now'))->getTimestamp() - $message->getCreatedAt()->getTimestamp(),
]);
}
private function sendDataDump(StoredObject $destinationStoredObject, RequestGenerationMessage $message): void
{
// Get the content of the document
$content = $this->storedObjectManager->read($destinationStoredObject);
$filename = $destinationStoredObject->getFilename();
$contentType = $destinationStoredObject->getType();
// Create the email with the document as an attachment
$email = (new TemplatedEmail())
->to($message->getSendResultToEmail())
->textTemplate('@ChillDocGenerator/Email/send_data_dump_to_admin.txt.twig')
->context([
'filename' => $filename,
])
->subject($this->translator->trans('docgen.data_dump_email.subject'))
->attach($content, $filename, $contentType);
$this->mailer->send($email);
}
}