diff --git a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php
index 4e2970138..ac832b34b 100644
--- a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php
+++ b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php
@@ -22,6 +22,7 @@ use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
+use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
@@ -45,6 +46,8 @@ class ActivityContext implements
private PersonRenderInterface $personRender;
+ private PersonRepository $personRepository;
+
private TranslatableStringHelperInterface $translatableStringHelper;
private TranslatorInterface $translator;
@@ -55,6 +58,7 @@ class ActivityContext implements
TranslatableStringHelperInterface $translatableStringHelper,
EntityManagerInterface $em,
PersonRenderInterface $personRender,
+ PersonRepository $personRepository,
TranslatorInterface $translator,
BaseContextData $baseContextData
) {
@@ -63,6 +67,7 @@ class ActivityContext implements
$this->translatableStringHelper = $translatableStringHelper;
$this->em = $em;
$this->personRender = $personRender;
+ $this->personRepository = $personRepository;
$this->translator = $translator;
$this->baseContextData = $baseContextData;
}
@@ -206,6 +211,32 @@ class ActivityContext implements
return $options['mainPerson'] || $options['person1'] || $options['person2'];
}
+ public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
+ {
+ $normalized = [];
+
+ foreach (['mainPerson', 'person1', 'person2'] as $k) {
+ $normalized[$k] = null === $data[$k] ? null : $data[$k]->getId();
+ }
+
+ return $normalized;
+ }
+
+ public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
+ {
+ $denormalized = [];
+
+ foreach (['mainPerson', 'person1', 'person2'] as $k) {
+ if (null !== ($id = ($data[$k] ?? null))) {
+ $denormalized[$k] = $this->personRepository->find($id);
+ } else {
+ $denormalized[$k] = null;
+ }
+ }
+
+ return $denormalized;
+ }
+
/**
* @param Activity $entity
*/
diff --git a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php
index 3189307f9..7e1873710 100644
--- a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php
+++ b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php
@@ -146,6 +146,16 @@ class ListActivitiesByAccompanyingPeriodContext implements
return $this->accompanyingPeriodContext->hasPublicForm($template, $entity);
}
+ public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
+ {
+ return $this->accompanyingPeriodContext->contextGenerationDataNormalize($template, $entity, $data);
+ }
+
+ public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
+ {
+ return $this->accompanyingPeriodContext->contextGenerationDataDenormalize($template, $entity, $data);
+ }
+
public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void
{
$this->accompanyingPeriodContext->storeGenerated($template, $storedObject, $entity, $contextGenerationData);
diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml
index 461137454..4dd67ceb8 100644
--- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml
@@ -77,7 +77,7 @@ Choose a type: Choisir un type
4 hours: 4 heures
4 hours 30: 4 heures 30
5 hours: 5 heures
-Concerned groups: Parties concernées
+Concerned groups: Parties concernées par l'échange
Persons in accompanying course: Usagers du parcours
Third persons: Tiers non-pro.
Others persons: Usagers
diff --git a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig
index df814282a..8978739ea 100644
--- a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig
+++ b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig
@@ -7,7 +7,7 @@
{# <=== vue component: mainUser #}
-{{ 'Concerned groups'|trans }}
+{{ 'Concerned groups calendar'|trans }}
{%- if form.persons is defined -%}
{{ form_widget(form.persons) }}
diff --git a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig
index 84eca97a0..9fff55d63 100644
--- a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig
+++ b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig
@@ -7,7 +7,7 @@
{# <=== vue component: mainUser #}
-{{ 'Concerned groups'|trans }}
+{{ 'Concerned groups calendar'|trans }}
{%- if form.mainUser is defined -%}
{{ form_row(form.mainUser) }}
diff --git a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/show.html.twig b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/show.html.twig
index bff4baa53..d48844f67 100644
--- a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/show.html.twig
+++ b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/show.html.twig
@@ -14,7 +14,7 @@
{{ entity.mainUser }}
-{{ 'Concerned groups'|trans }}
+{{ 'Concerned groups calendar'|trans }}
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': 'calendar_' ~ context, 'render': 'bloc' } %}
diff --git a/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContext.php b/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContext.php
index 9ba9e36b4..4984c359a 100644
--- a/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContext.php
+++ b/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContext.php
@@ -226,6 +226,16 @@ final class CalendarContext implements CalendarContextInterface
return true;
}
+ public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
+ {
+ // TODO: Implement publicFormTransform() method.
+ }
+
+ public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
+ {
+ // TODO: Implement publicFormReverseTransform() method.
+ }
+
/**
* @param array{mainPerson?: Person, thirdParty?: ThirdParty, title: string} $contextGenerationData
*/
diff --git a/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContextInterface.php b/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContextInterface.php
index d02cdc2c2..eeef3b417 100644
--- a/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContextInterface.php
+++ b/src/Bundle/ChillCalendarBundle/Service/DocGenerator/CalendarContextInterface.php
@@ -56,6 +56,10 @@ interface CalendarContextInterface extends DocGeneratorContextWithPublicFormInte
*/
public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool;
+ public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array;
+
+ public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array;
+
/**
* @param Calendar $entity
*/
diff --git a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml
index 623eb02cb..aa933bb63 100644
--- a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml
@@ -4,7 +4,7 @@ My calendar list: Mes rendez-vous
There is no calendar items.: Il n'y a pas de rendez-vous
Remove calendar item: Supprimer le rendez-vous
Are you sure you want to remove the calendar item?: Êtes-vous sûr de vouloir supprimer le rendez-vous?
-Concerned groups: Parties concernées
+Concerned groups calendar: Parties concernées
Calendar data: Données du rendez-vous
Update calendar: Modifier le rendez-vous
main user concerned: Utilisateur concerné
diff --git a/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextWithPublicFormInterface.php b/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextWithPublicFormInterface.php
index f013c8435..4f58bd049 100644
--- a/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextWithPublicFormInterface.php
+++ b/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextWithPublicFormInterface.php
@@ -23,6 +23,9 @@ interface DocGeneratorContextWithPublicFormInterface extends DocGeneratorContext
*/
public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void;
+ /**
+ * Fill the form with initial data
+ */
public function getFormData(DocGeneratorTemplate $template, $entity): array;
/**
@@ -31,4 +34,14 @@ interface DocGeneratorContextWithPublicFormInterface extends DocGeneratorContext
* @param mixed $entity
*/
public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool;
+
+ /**
+ * Transform the data from the form into serializable data, storable into messenger's message
+ */
+ public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array;
+
+ /**
+ * Reverse the data from the messenger's message into data usable for doc's generation
+ */
+ public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array;
}
diff --git a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php
index d618f758a..6f153acd8 100644
--- a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php
+++ b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php
@@ -16,67 +16,57 @@ use Chill\DocGeneratorBundle\Context\DocGeneratorContextWithPublicFormInterface;
use Chill\DocGeneratorBundle\Context\Exception\ContextNotFoundException;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocGeneratorBundle\GeneratorDriver\DriverInterface;
-use Chill\DocGeneratorBundle\GeneratorDriver\Exception\TemplateException;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
+use Chill\DocGeneratorBundle\Service\Generator\GeneratorInterface;
+use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Serializer\Model\Collection;
use Doctrine\ORM\EntityManagerInterface;
-use Exception;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
-use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
// TODO à mettre dans services
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
-use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Contracts\HttpClient\HttpClientInterface;
-use Throwable;
use function strlen;
final class DocGeneratorTemplateController extends AbstractController
{
- private HttpClientInterface $client;
-
private ContextManager $contextManager;
private DocGeneratorTemplateRepository $docGeneratorTemplateRepository;
- private DriverInterface $driver;
-
private EntityManagerInterface $entityManager;
- private LoggerInterface $logger;
+ private GeneratorInterface $generator;
+
+ private MessageBusInterface $messageBus;
private PaginatorFactory $paginatorFactory;
- private StoredObjectManagerInterface $storedObjectManager;
-
public function __construct(
ContextManager $contextManager,
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
- DriverInterface $driver,
- LoggerInterface $logger,
+ GeneratorInterface $generator,
+ MessageBusInterface $messageBus,
PaginatorFactory $paginatorFactory,
- HttpClientInterface $client,
- StoredObjectManagerInterface $storedObjectManager,
EntityManagerInterface $entityManager
) {
$this->contextManager = $contextManager;
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
- $this->driver = $driver;
- $this->logger = $logger;
+ $this->generator = $generator;
+ $this->messageBus = $messageBus;
$this->paginatorFactory = $paginatorFactory;
- $this->client = $client;
- $this->storedObjectManager = $storedObjectManager;
$this->entityManager = $entityManager;
}
@@ -94,7 +84,6 @@ final class DocGeneratorTemplateController extends AbstractController
): Response {
return $this->generateDocFromTemplate(
$template,
- $entityClassName,
$entityId,
$request,
true
@@ -115,7 +104,6 @@ final class DocGeneratorTemplateController extends AbstractController
): Response {
return $this->generateDocFromTemplate(
$template,
- $entityClassName,
$entityId,
$request,
false
@@ -185,7 +173,6 @@ final class DocGeneratorTemplateController extends AbstractController
private function generateDocFromTemplate(
DocGeneratorTemplate $template,
- string $entityClassName,
int $entityId,
Request $request,
bool $isTest
@@ -206,7 +193,7 @@ final class DocGeneratorTemplateController extends AbstractController
if (null === $entity) {
throw new NotFoundHttpException(
- sprintf('Entity with classname %s and id %s is not found', $entityClassName, $entityId)
+ sprintf('Entity with classname %s and id %s is not found', $context->getEntityClass(), $entityId)
);
}
@@ -259,99 +246,68 @@ final class DocGeneratorTemplateController extends AbstractController
}
}
- $document = $template->getFile();
-
- if ($isTest && ($contextGenerationData['test_file'] instanceof File)) {
- $dataDecrypted = file_get_contents($contextGenerationData['test_file']->getPathname());
- } else {
- try {
- $dataDecrypted = $this->storedObjectManager->read($document);
- } catch (Throwable $exception) {
- throw $exception;
- }
- }
+ // transform context generation data
+ $contextGenerationDataSanitized =
+ $context instanceof DocGeneratorContextWithPublicFormInterface ?
+ $context->contextGenerationDataNormalize($template, $entity, $contextGenerationData)
+ : [];
+ // if is test, render the data or generate the doc
if ($isTest && isset($form) && $form['show_data']->getData()) {
return $this->render('@ChillDocGenerator/Generator/debug_value.html.twig', [
'datas' => json_encode($context->getData($template, $entity, $contextGenerationData), JSON_PRETTY_PRINT)
]);
- }
-
- try {
- $generatedResource = $this
- ->driver
- ->generateFromString(
- $dataDecrypted,
- $template->getFile()->getType(),
- $context->getData($template, $entity, $contextGenerationData),
- $template->getFile()->getFilename()
- );
- } catch (TemplateException $e) {
- return new Response(
- implode("\n", $e->getErrors()),
- 400,
- [
- 'Content-Type' => 'text/plain',
- ]
+ } elseif ($isTest) {
+ $generated = $this->generator->generateDocFromTemplate(
+ $template,
+ $entityId,
+ $contextGenerationDataSanitized,
+ null,
+ true,
+ isset($form) ? $form['test_file']->getData() : null
);
- }
- if ($isTest) {
return new Response(
- $generatedResource,
+ $generated,
Response::HTTP_OK,
[
'Content-Transfer-Encoding', 'binary',
'Content-Type' => 'application/vnd.oasis.opendocument.text',
'Content-Disposition' => 'attachment; filename="generated.odt"',
- 'Content-Length' => strlen($generatedResource),
+ 'Content-Length' => strlen($generated),
],
);
}
- /** @var StoredObject $storedObject */
- $storedObject = (new ObjectNormalizer())
- ->denormalize(
- [
- 'type' => $template->getFile()->getType(),
- 'filename' => sprintf('%s_odt', uniqid('doc_', true)),
- ],
- StoredObject::class
- );
-
- try {
- $this->storedObjectManager->write($storedObject, $generatedResource);
- } catch (Throwable $exception) {
- throw $exception;
- }
+ // this is not a test
+ // we prepare the object to store the document
+ $storedObject = (new StoredObject())
+ ->setStatus(StoredObject::STATUS_PENDING)
+ ;
$this->entityManager->persist($storedObject);
- try {
- $context
- ->storeGenerated(
- $template,
- $storedObject,
- $entity,
- $contextGenerationData
- );
- } catch (Exception $e) {
- $this
- ->logger
- ->error(
- 'Unable to store the associated document to entity',
- [
- 'entityClassName' => $entityClassName,
- 'entityId' => $entityId,
- 'contextKey' => $context->getName(),
- ]
- );
-
- throw $e;
- }
+ // we store the generated document
+ $context
+ ->storeGenerated(
+ $template,
+ $storedObject,
+ $entity,
+ $contextGenerationData
+ );
$this->entityManager->flush();
+ $this->messageBus->dispatch(
+ new RequestGenerationMessage(
+ $this->getUser(),
+ $template,
+ $entityId,
+ $storedObject,
+ $contextGenerationDataSanitized,
+ )
+ );
+
return $this
->redirectToRoute(
'chill_wopi_file_edit',
diff --git a/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php
index 9f879f7ff..0f62931b4 100644
--- a/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php
+++ b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php
@@ -53,6 +53,7 @@ final class RelatorioDriver implements DriverInterface
$response = $this->client->request('POST', $this->url, [
'headers' => $form->getPreparedHeaders()->toArray(),
'body' => $form->bodyToIterable(),
+ 'timeout' => '300',
]);
return $response->getContent();
diff --git a/src/Bundle/ChillDocGeneratorBundle/Resources/views/Email/on_generation_failed_email.txt.twig b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Email/on_generation_failed_email.txt.twig
new file mode 100644
index 000000000..c4ca7079d
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Email/on_generation_failed_email.txt.twig
@@ -0,0 +1,16 @@
+{{ creator.label }},
+
+{{ 'docgen.failure_email.The generation of the document {template_name} failed'|trans({'{template_name}': template.name|localize_translatable_string}) }}
+
+{{ 'docgen.failure_email.Forward this email to your administrator for solving'|trans }}
+
+{{ 'docgen.failure_email.References'|trans }}:
+{% if errors|length > 0 %}
+{{ 'docgen.failure_email.The following errors were encoutered'|trans }}:
+
+{% for error in errors %}
+- {{ error }}
+{% endfor %}
+{% endif %}
+- template_id: {{ template.id }}
+- stored_object_destination_id: {{ stored_object_id }}
diff --git a/src/Bundle/ChillDocGeneratorBundle/Service/Generator/Generator.php b/src/Bundle/ChillDocGeneratorBundle/Service/Generator/Generator.php
new file mode 100644
index 000000000..0775cfb49
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/Service/Generator/Generator.php
@@ -0,0 +1,143 @@
+contextManager = $contextManager;
+ $this->driver = $driver;
+ $this->entityManager = $entityManager;
+ $this->logger = $logger;
+ $this->storedObjectManager = $storedObjectManager;
+ }
+
+ /**
+ * @template T of File|null
+ * @template B of bool
+ * @param B $isTest
+ * @param (B is true ? T : null) $testFile
+ * @psalm-return (B is true ? string : null)
+ * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface|\Throwable
+ */
+ public function generateDocFromTemplate(
+ DocGeneratorTemplate $template,
+ int $entityId,
+ array $contextGenerationDataNormalized,
+ ?StoredObject $destinationStoredObject = null,
+ bool $isTest = false,
+ ?File $testFile = null
+ ): ?string {
+ if ($destinationStoredObject instanceof StoredObject && StoredObject::STATUS_PENDING !== $destinationStoredObject->getStatus()) {
+ $this->logger->info(self::LOG_PREFIX.'Aborting generation of an already generated document');
+ throw new ObjectReadyException();
+ }
+
+ $this->logger->info(self::LOG_PREFIX.'Starting generation of a document', [
+ 'entity_id' => $entityId,
+ 'destination_stored_object' => $destinationStoredObject === null ? null : $destinationStoredObject->getId()
+ ]);
+
+ $context = $this->contextManager->getContextByDocGeneratorTemplate($template);
+
+ $entity = $this
+ ->entityManager
+ ->find($context->getEntityClass(), $entityId)
+ ;
+
+ if (null === $entity) {
+ throw new RelatedEntityNotFoundException($template->getEntity(), $entityId);
+ }
+
+ $contextGenerationDataNormalized = array_merge(
+ $contextGenerationDataNormalized,
+ $context instanceof DocGeneratorContextWithPublicFormInterface ?
+ $context->contextGenerationDataDenormalize($template, $entity, $contextGenerationDataNormalized)
+ : []
+ );
+
+ $data = $context->getData($template, $entity, $contextGenerationDataNormalized);
+
+ $destinationStoredObjectId = $destinationStoredObject instanceof StoredObject ? $destinationStoredObject->getId() : null;
+ $this->entityManager->clear();
+ gc_collect_cycles();
+ if (null !== $destinationStoredObjectId) {
+ $destinationStoredObject = $this->entityManager->find(StoredObject::class, $destinationStoredObjectId);
+ }
+
+ if ($isTest && ($testFile instanceof File)) {
+ $templateDecrypted = file_get_contents($testFile->getPathname());
+ } else {
+ $templateDecrypted = $this->storedObjectManager->read($template->getFile());
+ }
+
+ try {
+ $generatedResource = $this
+ ->driver
+ ->generateFromString(
+ $templateDecrypted,
+ $template->getFile()->getType(),
+ $data,
+ $template->getFile()->getFilename()
+ );
+ } catch (TemplateException $e) {
+ throw new GeneratorException($e->getErrors(), $e);
+ }
+
+ if ($isTest) {
+ $this->logger->info(self::LOG_PREFIX.'Finished generation of a document', [
+ 'is_test' => true,
+ 'entity_id' => $entityId,
+ 'destination_stored_object' => $destinationStoredObject === null ? null : $destinationStoredObject->getId()
+ ]);
+ return $generatedResource;
+ }
+
+ /** @var StoredObject $storedObject */
+ $destinationStoredObject
+ ->setType($template->getFile()->getType())
+ ->setFilename(sprintf('%s_odt', uniqid('doc_', true)))
+ ->setStatus(StoredObject::STATUS_READY)
+ ;
+
+ $this->storedObjectManager->write($destinationStoredObject, $generatedResource);
+
+ $this->entityManager->flush();
+
+ $this->logger->info(self::LOG_PREFIX.'Finished generation of a document', [
+ 'entity_id' => $entityId,
+ 'destination_stored_object' => $destinationStoredObject->getId(),
+ ]);
+
+ return null;
+ }
+}
diff --git a/src/Bundle/ChillDocGeneratorBundle/Service/Generator/GeneratorException.php b/src/Bundle/ChillDocGeneratorBundle/Service/Generator/GeneratorException.php
new file mode 100644
index 000000000..0f3412859
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/Service/Generator/GeneratorException.php
@@ -0,0 +1,26 @@
+
+ */
+ private array $errors;
+
+ public function __construct(array $errors = [], \Throwable $previous = null)
+ {
+ $this->errors = $errors;
+ parent::__construct("Could not generate the document", 15252,
+ $previous);
+ }
+
+ /**
+ * @return array
+ */
+ public function getErrors(): array
+ {
+ return $this->errors;
+ }
+}
diff --git a/src/Bundle/ChillDocGeneratorBundle/Service/Generator/GeneratorInterface.php b/src/Bundle/ChillDocGeneratorBundle/Service/Generator/GeneratorInterface.php
new file mode 100644
index 000000000..385e1d010
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/Service/Generator/GeneratorInterface.php
@@ -0,0 +1,27 @@
+docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
+ $this->entityManager = $entityManager;
+ $this->logger = $logger;
+ $this->mailer = $mailer;
+ $this->storedObjectRepository = $storedObjectRepository;
+ $this->translator = $translator;
+ $this->userRepository = $userRepository;
+ }
+
+
+ public static function getSubscribedEvents()
+ {
+ return [
+ WorkerMessageFailedEvent::class => 'onMessageFailed'
+ ];
+ }
+
+ public function onMessageFailed(WorkerMessageFailedEvent $event): void
+ {
+ if ($event->willRetry()) {
+ return;
+ }
+
+ if (!$event->getEnvelope()->getMessage() instanceof RequestGenerationMessage) {
+ return;
+ }
+
+ /** @var \Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage $message */
+ $message = $event->getEnvelope()->getMessage();
+
+ $this->logger->error(self::LOG_PREFIX.'Docgen failed', [
+ 'stored_object_id' => $message->getDestinationStoredObjectId(),
+ 'entity_id' => $message->getEntityId(),
+ 'template_id' => $message->getTemplateId(),
+ 'creator_id' => $message->getCreatorId(),
+ 'throwable_class' => get_class($event->getThrowable()),
+ ]);
+
+ $this->markObjectAsFailed($message);
+ $this->warnCreator($message, $event);
+ }
+
+ private function markObjectAsFailed(RequestGenerationMessage $message): void
+ {
+ $object = $this->storedObjectRepository->find($message->getDestinationStoredObjectId());
+
+ if (null === $object) {
+ $this->logger->error(self::LOG_PREFIX.'Stored object not found', ['stored_object_id', $message->getDestinationStoredObjectId()]);
+ }
+
+ $object->setStatus(StoredObject::STATUS_FAILURE);
+
+ $this->entityManager->flush();
+ }
+
+ private function warnCreator(RequestGenerationMessage $message, WorkerMessageFailedEvent $event): void
+ {
+ if (null === $creatorId = $message->getCreatorId()) {
+ $this->logger->info(self::LOG_PREFIX.'creator id is null');
+ return;
+ }
+
+ if (null === $creator = $this->userRepository->find($creatorId)) {
+ $this->logger->error(self::LOG_PREFIX.'Creator not found with given id', ['creator_id', $creatorId]);
+ return;
+ }
+
+ if (null === $creator->getEmail() || '' === $creator->getEmail()) {
+ $this->logger->info(self::LOG_PREFIX.'Creator does not have any email', ['user' => $creator->getUsernameCanonical()]);
+ return;
+ }
+
+ // if the exception is not a GeneratorException, we try the previous one...
+ $throwable = $event->getThrowable();
+ if (!$throwable instanceof GeneratorException) {
+ $throwable = $throwable->getPrevious();
+ }
+
+ if ($throwable instanceof GeneratorException) {
+ $errors = $throwable->getErrors();
+ } else {
+ $errors = [$throwable->getTraceAsString()];
+ }
+
+ if (null === $template = $this->docGeneratorTemplateRepository->find($message->getTemplateId())) {
+ $this->logger->info(self::LOG_PREFIX.'Template not found', ['template_id' => $message->getTemplateId()]);
+ return;
+ }
+
+ $email = (new TemplatedEmail())
+ ->to($creator->getEmail())
+ ->subject($this->translator->trans('docgen.failure_email.The generation of a document failed'))
+ ->textTemplate('@ChillDocGenerator/Email/on_generation_failed_email.txt.twig')
+ ->context([
+ 'errors' => $errors,
+ 'template' => $template,
+ 'creator' => $creator,
+ 'stored_object_id' => $message->getDestinationStoredObjectId(),
+ ]);
+
+ $this->mailer->send($email);
+ }
+}
diff --git a/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationHandler.php b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationHandler.php
new file mode 100644
index 000000000..0cfdecd0a
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationHandler.php
@@ -0,0 +1,66 @@
+docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
+ $this->entityManager = $entityManager;
+ $this->generator = $generator;
+ $this->storedObjectRepository = $storedObjectRepository;
+ }
+
+ 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) {
+ throw new UnrecoverableMessageHandlingException('maximum number of retry reached');
+ }
+
+ $destinationStoredObject->addGenerationTrial();
+ $this->entityManager->createQuery('UPDATE '.StoredObject::class.' s SET s.generationTrialsCounter = s.generationTrialsCounter + 1 WHERE s.id = :id')
+ ->setParameter('id', $destinationStoredObject->getId())
+ ->execute();
+
+ $this->generator->generateDocFromTemplate(
+ $template,
+ $message->getEntityId(),
+ $message->getContextGenerationData(),
+ $destinationStoredObject
+ );
+ }
+}
diff --git a/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationMessage.php b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationMessage.php
new file mode 100644
index 000000000..edba90ce4
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationMessage.php
@@ -0,0 +1,59 @@
+creatorId = $creator->getId();
+ $this->templateId = $template->getId();
+ $this->entityId = $entityId;
+ $this->destinationStoredObjectId = $destinationStoredObject->getId();
+ $this->contextGenerationData = $contextGenerationData;
+ }
+
+ public function getCreatorId(): int
+ {
+ return $this->creatorId;
+ }
+
+ public function getDestinationStoredObjectId(): int
+ {
+ return $this->destinationStoredObjectId;
+ }
+
+ public function getTemplateId(): int
+ {
+ return $this->templateId;
+ }
+
+ public function getEntityId(): int
+ {
+ return $this->entityId;
+ }
+
+ public function getContextGenerationData(): array
+ {
+ return $this->contextGenerationData;
+ }
+}
diff --git a/src/Bundle/ChillDocGeneratorBundle/config/services.yaml b/src/Bundle/ChillDocGeneratorBundle/config/services.yaml
index 5bdfe2a11..5fef6fb22 100644
--- a/src/Bundle/ChillDocGeneratorBundle/config/services.yaml
+++ b/src/Bundle/ChillDocGeneratorBundle/config/services.yaml
@@ -20,10 +20,14 @@ services:
resource: '../Serializer/Normalizer/'
tags:
- { name: 'serializer.normalizer', priority: -152 }
+
Chill\DocGeneratorBundle\Serializer\Normalizer\CollectionDocGenNormalizer:
tags:
- { name: 'serializer.normalizer', priority: -126 }
+ Chill\DocGeneratorBundle\Service\Context\:
+ resource: "../Service/Context"
+
Chill\DocGeneratorBundle\Controller\:
resource: "../Controller"
autowire: true
@@ -34,18 +38,20 @@ services:
autowire: true
autoconfigure: true
- Chill\DocGeneratorBundle\Service\Context\:
- resource: "../Service/Context/"
- autowire: true
- autoconfigure: true
-
Chill\DocGeneratorBundle\GeneratorDriver\:
resource: "../GeneratorDriver/"
autowire: true
autoconfigure: true
+ Chill\DocGeneratorBundle\Service\Messenger\:
+ resource: "../Service/Messenger/"
+
+ Chill\DocGeneratorBundle\Service\Generator\Generator: ~
+ Chill\DocGeneratorBundle\Service\Generator\GeneratorInterface: '@Chill\DocGeneratorBundle\Service\Generator\Generator'
+
Chill\DocGeneratorBundle\Driver\RelatorioDriver: '@Chill\DocGeneratorBundle\Driver\DriverInterface'
Chill\DocGeneratorBundle\Context\ContextManager:
arguments:
$contexts: !tagged_iterator { tag: chill_docgen.context, default_index_method: getKey }
+ Chill\DocGeneratorBundle\Context\ContextManagerInterface: '@Chill\DocGeneratorBundle\Context\ContextManager'
diff --git a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20230214192558.php b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20230214192558.php
new file mode 100644
index 000000000..de536ca84
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20230214192558.php
@@ -0,0 +1,47 @@
+addSql('ALTER TABLE chill_doc.stored_object ADD template_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ADD status TEXT DEFAULT \'ready\' NOT NULL');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ADD createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
+ $this->addSql('UPDATE chill_doc.stored_object SET createdAt = creation_date');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ADD createdBy_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_doc.stored_object DROP creation_date;');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ALTER type SET DEFAULT \'\'');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ALTER title DROP DEFAULT');
+ $this->addSql('COMMENT ON COLUMN chill_doc.stored_object.createdAt IS \'(DC2Type:datetime_immutable)\'');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ADD CONSTRAINT FK_49604E365DA0FB8 FOREIGN KEY (template_id) REFERENCES chill_docgen_template (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ADD CONSTRAINT FK_49604E363174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('CREATE INDEX IDX_49604E365DA0FB8 ON chill_doc.stored_object (template_id)');
+ $this->addSql('CREATE INDEX IDX_49604E363174800F ON chill_doc.stored_object (createdBy_id)');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE chill_doc.stored_object DROP CONSTRAINT FK_49604E365DA0FB8');
+ $this->addSql('ALTER TABLE chill_doc.stored_object DROP CONSTRAINT FK_49604E363174800F');
+ $this->addSql('ALTER TABLE chill_doc.stored_object DROP template_id');
+ $this->addSql('ALTER TABLE chill_doc.stored_object DROP status');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ADD creation_date TIMESTAMP(0) DEFAULT NOW()');
+ $this->addSql('UPDATE chill_doc.stored_object SET creation_date = createdAt');
+ $this->addSql('ALTER TABLE chill_doc.stored_object DROP createdAt');
+ $this->addSql('ALTER TABLE chill_doc.stored_object DROP createdBy_id');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ALTER title SET DEFAULT \'\'');
+ $this->addSql('ALTER TABLE chill_doc.stored_object ALTER type DROP DEFAULT');
+ }
+}
diff --git a/src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/Generator/GeneratorTest.php b/src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/Generator/GeneratorTest.php
new file mode 100644
index 000000000..066715b60
--- /dev/null
+++ b/src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/Generator/GeneratorTest.php
@@ -0,0 +1,141 @@
+setFile($templateStoredObject = (new StoredObject())
+ ->setType('application/test'));
+ $destinationStoredObject = (new StoredObject())->setStatus(StoredObject::STATUS_PENDING);
+ $reflection = new \ReflectionClass($destinationStoredObject);
+ $reflection->getProperty('id')->setAccessible(true);
+ $reflection->getProperty('id')->setValue($destinationStoredObject, 1);
+ $entity = new class {};
+ $data = [];
+
+ $context = $this->prophesize(DocGeneratorContextInterface::class);
+ $context->getData($template, $entity, Argument::type('array'))->willReturn($data);
+ $context->getName()->willReturn('dummy_context');
+ $context->getEntityClass()->willReturn('DummyClass');
+ $context = $context->reveal();
+
+ $contextManagerInterface = $this->prophesize(ContextManagerInterface::class);
+ $contextManagerInterface->getContextByDocGeneratorTemplate($template)
+ ->willReturn($context);
+
+ $driver = $this->prophesize(DriverInterface::class);
+ $driver->generateFromString('template', 'application/test', $data, Argument::any())
+ ->willReturn('generated');
+
+ $entityManager = $this->prophesize(EntityManagerInterface::class);
+ $entityManager->find(StoredObject::class, 1)
+ ->willReturn($destinationStoredObject);
+ $entityManager->find('DummyClass', Argument::type('int'))
+ ->willReturn($entity);
+ $entityManager->clear()->shouldBeCalled();
+ $entityManager->flush()->shouldBeCalled();
+
+ $storedObjectManager = $this->prophesize(StoredObjectManagerInterface::class);
+ $storedObjectManager->read($templateStoredObject)->willReturn('template');
+ $storedObjectManager->write($destinationStoredObject, 'generated')->shouldBeCalled();
+
+
+ $generator = new Generator(
+ $contextManagerInterface->reveal(),
+ $driver->reveal(),
+ $entityManager->reveal(),
+ new NullLogger(),
+ $storedObjectManager->reveal()
+ );
+
+ $generator->generateDocFromTemplate(
+ $template,
+ 1,
+ [],
+ $destinationStoredObject
+ );
+ }
+
+ public function testPreventRegenerateDocument(): void
+ {
+ $this->expectException(ObjectReadyException::class);
+
+ $generator = new Generator(
+ $this->prophesize(ContextManagerInterface::class)->reveal(),
+ $this->prophesize(DriverInterface::class)->reveal(),
+ $this->prophesize(EntityManagerInterface::class)->reveal(),
+ new NullLogger(),
+ $this->prophesize(StoredObjectManagerInterface::class)->reveal()
+ );
+
+ $template = (new DocGeneratorTemplate())->setFile($templateStoredObject = (new StoredObject())
+ ->setType('application/test'));
+ $destinationStoredObject = (new StoredObject())->setStatus(StoredObject::STATUS_READY);
+
+ $generator->generateDocFromTemplate(
+ $template,
+ 1,
+ [],
+ $destinationStoredObject
+ );
+ }
+
+ public function testRelatedEntityNotFound(): void
+ {
+ $this->expectException(RelatedEntityNotFoundException::class);
+
+ $template = (new DocGeneratorTemplate())->setFile($templateStoredObject = (new StoredObject())
+ ->setType('application/test'));
+ $destinationStoredObject = (new StoredObject())->setStatus(StoredObject::STATUS_PENDING);
+ $reflection = new \ReflectionClass($destinationStoredObject);
+ $reflection->getProperty('id')->setAccessible(true);
+ $reflection->getProperty('id')->setValue($destinationStoredObject, 1);
+
+ $context = $this->prophesize(DocGeneratorContextInterface::class);
+ $context->getName()->willReturn('dummy_context');
+ $context->getEntityClass()->willReturn('DummyClass');
+ $context = $context->reveal();
+
+ $contextManagerInterface = $this->prophesize(ContextManagerInterface::class);
+ $contextManagerInterface->getContextByDocGeneratorTemplate($template)
+ ->willReturn($context);
+
+ $entityManager = $this->prophesize(EntityManagerInterface::class);
+ $entityManager->find(Argument::type('string'), Argument::type('int'))
+ ->willReturn(null);
+
+ $generator = new Generator(
+ $contextManagerInterface->reveal(),
+ $this->prophesize(DriverInterface::class)->reveal(),
+ $entityManager->reveal(),
+ new NullLogger(),
+ $this->prophesize(StoredObjectManagerInterface::class)->reveal()
+ );
+
+ $generator->generateDocFromTemplate(
+ $template,
+ 1,
+ [],
+ $destinationStoredObject
+ );
+ }
+}
diff --git a/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml b/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml
index bf37ff838..d0950482e 100644
--- a/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml
@@ -10,6 +10,16 @@ docgen:
test generate: Tester la génération
With context %name%: 'Avec le contexte "%name%"'
+ Doc generation failed: La génération de ce document a échoué
+ Doc generation is pending: La génération de ce document est en cours
+ Come back later: Revenir plus tard
+
+ failure_email:
+ The generation of a document failed: La génération d'un document a échoué
+ The generation of the document {template_name} failed: La génération d'un document à partir du modèle {{ template_name }} a échoué.
+ The following errors were encoutered: Les erreurs suivantes ont été rencontrées
+ Forward this email to your administrator for solving: Faites suivre ce message vers votre administrateur pour la résolution du problème.
+ References: Références
crud:
docgen_template:
@@ -19,4 +29,4 @@ crud:
Show data instead of generating: Montrer les données au lieu de générer le document
-Template file: Fichier modèle
\ No newline at end of file
+Template file: Fichier modèle
diff --git a/src/Bundle/ChillDocStoreBundle/Controller/StoredObjectApiController.php b/src/Bundle/ChillDocStoreBundle/Controller/StoredObjectApiController.php
new file mode 100644
index 000000000..29b978ffb
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Controller/StoredObjectApiController.php
@@ -0,0 +1,39 @@
+security = $security;
+ }
+
+ /**
+ * @Route("/api/1.0/doc-store/stored-object/{uuid}/is-ready")
+ */
+ public function isDocumentReady(StoredObject $storedObject): Response
+ {
+ if (!$this->security->isGranted('ROLE_USER')) {
+ throw new AccessDeniedHttpException();
+ }
+
+ return new JsonResponse(
+ [
+ 'id' => $storedObject->getId(),
+ 'filename' => $storedObject->getFilename(),
+ 'status' => $storedObject->getStatus(),
+ 'type' => $storedObject->getType(),
+ ]
+ );
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php
index ec2b67cf2..8821ead7c 100644
--- a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php
+++ b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php
@@ -14,6 +14,9 @@ namespace Chill\DocStoreBundle\Entity;
use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface;
use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists;
use ChampsLibres\WopiLib\Contract\Entity\Document;
+use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
+use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
+use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use DateTime;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
@@ -30,13 +33,13 @@ use Symfony\Component\Serializer\Annotation as Serializer;
* message="The file is not stored properly"
* )
*/
-class StoredObject implements AsyncFileInterface, Document
+class StoredObject implements AsyncFileInterface, Document, TrackCreationInterface
{
- /**
- * @ORM\Column(type="datetime", name="creation_date")
- * @Serializer\Groups({"read", "write"})
- */
- private DateTimeInterface $creationDate;
+ public const STATUS_READY = "ready";
+ public const STATUS_PENDING = "pending";
+ public const STATUS_FAILURE = "failure";
+
+ use TrackCreationTrait;
/**
* @ORM\Column(type="json", name="datas")
@@ -48,7 +51,7 @@ class StoredObject implements AsyncFileInterface, Document
* @ORM\Column(type="text")
* @Serializer\Groups({"read", "write"})
*/
- private $filename;
+ private string $filename = '';
/**
* @ORM\Id
@@ -56,7 +59,7 @@ class StoredObject implements AsyncFileInterface, Document
* @ORM\Column(type="integer")
* @Serializer\Groups({"read", "write"})
*/
- private $id;
+ private ?int $id;
/**
* @var int[]
@@ -78,7 +81,7 @@ class StoredObject implements AsyncFileInterface, Document
private string $title = '';
/**
- * @ORM\Column(type="text", name="type")
+ * @ORM\Column(type="text", name="type", options={"default": ""})
* @Serializer\Groups({"read", "write"})
*/
private string $type = '';
@@ -89,28 +92,68 @@ class StoredObject implements AsyncFileInterface, Document
*/
private UuidInterface $uuid;
- public function __construct()
+ /**
+ * @ORM\ManyToOne(targetEntity=DocGeneratorTemplate::class)
+ */
+ private ?DocGeneratorTemplate $template;
+
+ /**
+ * @ORM\Column(type="text", options={"default": "ready"})
+ * @Serializer\Groups({"read"})
+ */
+ private string $status;
+
+ /**
+ * Store the number of times a generation has been tryied for this StoredObject.
+ *
+ * This is a workaround, as generation consume lot of memory, and out-of-memory errors
+ * are not handled by messenger.
+ *
+ * @ORM\Column(type="integer", options={"default": 0})
+ */
+ private int $generationTrialsCounter = 0;
+
+ /**
+ * @param StoredObject::STATUS_* $status
+ */
+ public function __construct(string $status = "ready")
{
- $this->creationDate = new DateTime();
$this->uuid = Uuid::uuid4();
+ $this->status = $status;
}
+ public function addGenerationTrial(): self
+ {
+ $this->generationTrialsCounter++;
+
+ return $this;
+ }
+
+ /**
+ * @Serializer\Groups({"read", "write"})
+ * @deprecated
+ */
public function getCreationDate(): DateTime
{
- return $this->creationDate;
+ return DateTime::createFromImmutable($this->createdAt);
}
- public function getDatas()
+ public function getDatas(): array
{
return $this->datas;
}
- public function getFilename()
+ public function getFilename(): string
{
return $this->filename;
}
- public function getId()
+ public function getGenerationTrialsCounter(): int
+ {
+ return $this->generationTrialsCounter;
+ }
+
+ public function getId(): ?int
{
return $this->id;
}
@@ -133,6 +176,14 @@ class StoredObject implements AsyncFileInterface, Document
return $this->getFilename();
}
+ /**
+ * @return StoredObject::STATUS_*
+ */
+ public function getStatus(): string
+ {
+ return $this->status;
+ }
+
public function getTitle()
{
return $this->title;
@@ -153,52 +204,92 @@ class StoredObject implements AsyncFileInterface, Document
return (string) $this->uuid;
}
- public function setCreationDate(DateTime $creationDate)
+ /**
+ * @Serializer\Groups({"write"})
+ * @deprecated
+ */
+ public function setCreationDate(DateTime $creationDate): self
{
- $this->creationDate = $creationDate;
+ $this->createdAt = \DateTimeImmutable::createFromMutable($creationDate);
return $this;
}
- public function setDatas(?array $datas)
+ public function setDatas(?array $datas): self
{
$this->datas = (array) $datas;
return $this;
}
- public function setFilename(?string $filename)
+ public function setFilename(?string $filename): self
{
$this->filename = (string) $filename;
return $this;
}
- public function setIv(?array $iv)
+ public function setIv(?array $iv): self
{
$this->iv = (array) $iv;
return $this;
}
- public function setKeyInfos(?array $keyInfos)
+ public function setKeyInfos(?array $keyInfos): self
{
$this->keyInfos = (array) $keyInfos;
return $this;
}
- public function setTitle(?string $title)
+ /**
+ * @param StoredObject::STATUS_* $status
+ */
+ public function setStatus(string $status): self
+ {
+ $this->status = $status;
+
+ return $this;
+ }
+
+ public function setTitle(?string $title): self
{
$this->title = (string) $title;
return $this;
}
- public function setType(?string $type)
+ public function setType(?string $type): self
{
$this->type = (string) $type;
return $this;
}
+
+ public function getTemplate(): ?DocGeneratorTemplate
+ {
+ return $this->template;
+ }
+
+ public function hasTemplate(): bool
+ {
+ return null !== $this->template;
+ }
+
+ public function setTemplate(?DocGeneratorTemplate $template): StoredObject
+ {
+ $this->template = $template;
+ return $this;
+ }
+
+ public function isPending(): bool
+ {
+ return self::STATUS_PENDING === $this->getStatus();
+ }
+
+ public function isFailure(): bool
+ {
+ return self::STATUS_FAILURE === $this->getStatus();
+ }
}
diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/module/document_action_buttons_group/index.ts b/src/Bundle/ChillDocStoreBundle/Resources/public/module/document_action_buttons_group/index.ts
index ec1d50a86..e5912d38a 100644
--- a/src/Bundle/ChillDocStoreBundle/Resources/public/module/document_action_buttons_group/index.ts
+++ b/src/Bundle/ChillDocStoreBundle/Resources/public/module/document_action_buttons_group/index.ts
@@ -1,7 +1,8 @@
import {_createI18n} from "../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
import DocumentActionButtonsGroup from "../../vuejs/DocumentActionButtonsGroup.vue";
import {createApp} from "vue";
-import {StoredObject} from "../../types";
+import {StoredObject, StoredObjectStatusChange} from "../../types";
+import {is_object_ready} from "../../vuejs/StoredObjectButton/helpers";
const i18n = _createI18n({});
@@ -19,7 +20,7 @@ window.addEventListener('DOMContentLoaded', function (e) {
};
const
- storedObject = JSON.parse(datasets.storedObject),
+ storedObject = JSON.parse(datasets.storedObject) as StoredObject,
filename = datasets.filename,
canEdit = datasets.canEdit === '1',
small = datasets.small === '1'
@@ -27,7 +28,20 @@ window.addEventListener('DOMContentLoaded', function (e) {
return { storedObject, filename, canEdit, small };
},
- template: '',
+ template: '',
+ methods: {
+ onStoredObjectStatusChange: function(newStatus: StoredObjectStatusChange): void {
+ this.$data.storedObject.status = newStatus.status;
+ this.$data.storedObject.filename = newStatus.filename;
+ this.$data.storedObject.type = newStatus.type;
+
+ // remove eventual div which inform pending status
+ document.querySelectorAll(`[data-docgen-is-pending="${this.$data.storedObject.id}"]`)
+ .forEach(function(el) {
+ el.remove();
+ });
+ }
+ }
});
app.use(i18n).mount(el);
diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/types.ts b/src/Bundle/ChillDocStoreBundle/Resources/public/types.ts
index 918526117..825055973 100644
--- a/src/Bundle/ChillDocStoreBundle/Resources/public/types.ts
+++ b/src/Bundle/ChillDocStoreBundle/Resources/public/types.ts
@@ -1,5 +1,7 @@
import {DateTime} from "../../../ChillMainBundle/Resources/public/types";
+export type StoredObjectStatus = "ready"|"failure"|"pending";
+
export interface StoredObject {
id: number,
@@ -13,7 +15,15 @@ export interface StoredObject {
keyInfos: object,
title: string,
type: string,
- uuid: string
+ uuid: string,
+ status: StoredObjectStatus,
+}
+
+export interface StoredObjectStatusChange {
+ id: number,
+ filename: string,
+ status: StoredObjectStatus,
+ type: string,
}
/**
diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentActionButtonsGroup.vue b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentActionButtonsGroup.vue
index 60b368cd3..ac841f5cf 100644
--- a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentActionButtonsGroup.vue
+++ b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentActionButtonsGroup.vue
@@ -1,5 +1,5 @@
-
+
@@ -15,16 +15,27 @@
+
+
+
La génération a échoué
+