chill-bundles/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php

289 lines
11 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\Controller;
use Chill\DocGeneratorBundle\Context\ContextManager;
use Chill\DocGeneratorBundle\Context\DocGeneratorContextWithPublicFormInterface;
use Chill\DocGeneratorBundle\Context\Exception\ContextNotFoundException;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Form\Type\PickUserDynamicType;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Security\ChillSecurity;
use Chill\MainBundle\Serializer\Model\Collection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
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\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
final class DocGeneratorTemplateController extends AbstractController
{
public function __construct(
private readonly ContextManager $contextManager,
private readonly DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
private readonly MessageBusInterface $messageBus,
private readonly PaginatorFactory $paginatorFactory,
private readonly EntityManagerInterface $entityManager,
private readonly ClockInterface $clock,
private readonly ChillSecurity $security,
) {}
#[Route(path: '{_locale}/admin/doc/gen/generate/test/from/{template}/for/{entityClassName}/{entityId}', name: 'chill_docgenerator_test_generate_from_template')]
public function adminTestGenerateDocFromTemplateAction(
DocGeneratorTemplate $template,
string $entityClassName,
int $entityId,
Request $request,
): Response {
return $this->generateDocFromTemplate(
$template,
$entityId,
$request,
true
);
}
#[Route(path: '{_locale}/doc/gen/generate/from/{template}/for/{entityClassName}/{entityId}', name: 'chill_docgenerator_generate_from_template')]
public function generateDocFromTemplateAction(
DocGeneratorTemplate $template,
string $entityClassName,
int $entityId,
Request $request,
): Response {
return $this->generateDocFromTemplate(
$template,
$entityId,
$request,
false
);
}
#[Route(path: '/api/1.0/docgen/templates/by-entity/{entityClassName}', name: 'chill_docgenerator_templates_for_entity_api')]
public function listTemplateApiAction(string $entityClassName): Response
{
$nb = $this->docGeneratorTemplateRepository->countByEntity($entityClassName);
$paginator = $this->paginatorFactory->create($nb);
$entities = $this->docGeneratorTemplateRepository->findByEntity(
$entityClassName,
$paginator->getCurrentPageFirstItemNumber(),
$paginator->getItemsPerPage()
);
return $this->json(
new Collection($entities, $paginator),
Response::HTTP_OK,
[],
[AbstractNormalizer::GROUPS => ['read']]
);
}
/**
* @return void
*/
#[Route(path: '{_locale}/admin/doc/gen/generate/test/redirect', name: 'chill_docgenerator_test_generate_redirect')]
public function redirectToTestGenerate(Request $request): RedirectResponse
{
$template = $request->query->getInt('template');
if (null === $template) {
throw new BadRequestHttpException('template parameter is missing');
}
$entityClassName = $request->query->get('entityClassName');
if (null === $entityClassName) {
throw new BadRequestHttpException('entityClassName is missing');
}
$entityId = $request->query->get('entityId');
if (null === $entityId) {
throw new BadRequestHttpException('entityId is missing');
}
return $this->redirectToRoute(
'chill_docgenerator_test_generate_from_template',
[
'template' => $template, 'entityClassName' => $entityClassName, 'entityId' => $entityId,
'returnPath' => $request->query->get('returnPath', '/'),
]
);
}
private function generateDocFromTemplate(
DocGeneratorTemplate $template,
int $entityId,
Request $request,
bool $isTest,
): Response {
try {
$context = $this->contextManager->getContextByDocGeneratorTemplate($template);
} catch (ContextNotFoundException $e) {
throw new NotFoundHttpException('Context not found.', $e);
}
$entity = $this
->entityManager
->getRepository($context->getEntityClass())
->find($entityId);
if (null === $entity) {
throw new NotFoundHttpException(sprintf('Entity with classname %s and id %s is not found', $context->getEntityClass(), $entityId));
}
$contextGenerationData = [];
if (
$context instanceof DocGeneratorContextWithPublicFormInterface
&& $context->hasPublicForm($template, $entity) || $isTest
) {
if ($context instanceof DocGeneratorContextWithPublicFormInterface && $context->hasPublicForm($template, $entity)) {
$builder = $this->createFormBuilder(
array_merge(
$context->getFormData($template, $entity),
$isTest ? ['creator' => null, 'dump_only' => false, 'send_result_to' => ''] : []
)
);
$context->buildPublicForm($builder, $template, $entity);
} else {
$builder = $this->createFormBuilder(
['creator' => null, 'show_data' => false, 'send_result_to' => '']
);
}
if ($isTest) {
$builder->add('dump_only', CheckboxType::class, [
'label' => 'docgen.Show data instead of generating',
'required' => false,
]);
$builder->add('send_result_to', EmailType::class, [
'label' => 'docgen.Send report to',
'help' => 'docgen.Send report errors to this email address',
'empty_data' => '',
'required' => true,
'constraints' => [
new NotBlank(),
new NotNull(),
],
]);
$builder->add('creator', PickUserDynamicType::class, [
'label' => 'docgen.Generate as creator',
'help' => 'docgen.The document will be generated as the given creator',
'multiple' => false,
'constraints' => [
new NotNull(),
],
]);
}
$form = $builder->getForm()->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$contextGenerationData = $form->getData();
} elseif (!$form->isSubmitted() || ($form->isSubmitted() && !$form->isValid())) {
$templatePath = '@ChillDocGenerator/Generator/basic_form.html.twig';
$templateOptions = [
'entity' => $entity,
'form' => $form->createView(),
'template' => $template,
'context' => $context,
];
return $this->render($templatePath, $templateOptions);
}
}
// transform context generation data
$contextGenerationDataSanitized =
$context instanceof DocGeneratorContextWithPublicFormInterface ?
$context->contextGenerationDataNormalize($template, $entity, $contextGenerationData)
: [];
// we prepare the object to store the document
$storedObject = (new StoredObject())
->setStatus(StoredObject::STATUS_PENDING)
;
if ($isTest) {
// document will be stored during 15 days, if generation is a test
$storedObject->setDeleteAt($this->clock->now()->add(new \DateInterval('P15D')));
}
$this->entityManager->persist($storedObject);
// we store the generated document (associate with the original entity, etc.)
// but only if this is not a test
if (!$isTest) {
$context
->storeGenerated(
$template,
$storedObject,
$entity,
$contextGenerationData
);
}
$this->entityManager->flush();
if ($isTest) {
$creator = $contextGenerationData['creator'];
$sendResultTo = ($form ?? null)?->get('send_result_to')?->getData() ?? null;
$dumpOnly = ($form ?? null)?->get('dump_only')?->getData() ?? false;
} else {
if (!$this->isGranted('ROLE_USER')) {
throw new AccessDeniedHttpException('only authenticated user can request a generation');
}
$creator = $this->security->getUser();
$sendResultTo = null;
$dumpOnly = false;
}
$this->messageBus->dispatch(
new RequestGenerationMessage(
$creator,
$template,
$entityId,
$storedObject,
$contextGenerationDataSanitized,
$isTest,
$sendResultTo,
$dumpOnly,
)
);
return $this
->redirectToRoute(
'chill_wopi_file_edit',
[
'fileId' => $storedObject->getUuid(),
'returnPath' => $request->query->get('returnPath', '/'),
]
);
}
}