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

295 lines
10 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\Generator\GeneratorInterface;
use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage;
use Chill\DocStoreBundle\Entity\StoredObject;
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\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
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;
final class DocGeneratorTemplateController extends AbstractController
{
public function __construct(
private readonly ContextManager $contextManager,
private readonly DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
private readonly GeneratorInterface $generator,
private readonly MessageBusInterface $messageBus,
private readonly PaginatorFactory $paginatorFactory,
private readonly EntityManagerInterface $entityManager,
private readonly ChillSecurity $security
) {}
/**
* @Route(
* "{_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(
* "{_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(
* "/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']]
);
}
/**
* @Route(
* "{_locale}/admin/doc/gen/generate/test/redirect",
* name="chill_docgenerator_test_generate_redirect"
* )
*
* @return void
*/
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 = [
'test_file' => null,
];
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 ? ['test_file' => null, 'show_data' => false] : []
)
);
$context->buildPublicForm($builder, $template, $entity);
} else {
$builder = $this->createFormBuilder(
['test_file' => null, 'show_data' => false]
);
}
if ($isTest) {
$builder->add('test_file', FileType::class, [
'label' => 'Template file',
'required' => false,
]);
$builder->add('show_data', CheckboxType::class, [
'label' => 'Show data instead of generating',
'required' => false,
]);
}
$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)
: [];
// if is test, render the data or generate the doc
if ($isTest && isset($form) && true === $form['show_data']->getData()) {
return $this->render('@ChillDocGenerator/Generator/debug_value.html.twig', [
'datas' => json_encode($context->getData($template, $entity, $contextGenerationData), \JSON_PRETTY_PRINT),
]);
}
if ($isTest) {
$generated = $this->generator->generateDocFromTemplate(
$template,
$entityId,
$contextGenerationDataSanitized,
null,
true,
isset($form) ? $form['test_file']->getData() : null
);
return new Response(
$generated,
Response::HTTP_OK,
[
'Content-Transfer-Encoding', 'binary',
'Content-Type' => 'application/vnd.oasis.opendocument.text',
'Content-Disposition' => 'attachment; filename="generated.odt"',
'Content-Length' => \strlen($generated),
],
);
}
// this is not a test
// we prepare the object to store the document
$storedObject = (new StoredObject())
->setStatus(StoredObject::STATUS_PENDING)
;
$this->entityManager->persist($storedObject);
// we store the generated document
$context
->storeGenerated(
$template,
$storedObject,
$entity,
$contextGenerationData
);
$this->entityManager->flush();
$this->messageBus->dispatch(
new RequestGenerationMessage(
$this->security->getUser(),
$template,
$entityId,
$storedObject,
$contextGenerationDataSanitized,
)
);
return $this
->redirectToRoute(
'chill_wopi_file_edit',
[
'fileId' => $storedObject->getUuid(),
'returnPath' => $request->query->get('returnPath', '/'),
]
);
}
}