diff --git a/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php b/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php index 78b59fdc6..8dfecb730 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php +++ b/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php @@ -40,6 +40,17 @@ class ContextManager throw new ContextNotFoundException($docGeneratorTemplate->getContext()); } + public function getContextByKey(string $searchedKey): DocGeneratorContextInterface + { + foreach ($this->contexts as $key => $context) { + if ($searchedKey === $key) { + return $context; + } + } + + throw new ContextNotFoundException($searchedKey); + } + public function getContexts(): array { return iterator_to_array($this->contexts); diff --git a/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php b/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php index f70aa0abf..d9faeeb3f 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php +++ b/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php @@ -13,9 +13,10 @@ namespace Chill\DocGeneratorBundle\Context; use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; use Chill\DocStoreBundle\Entity\StoredObject; +use Symfony\Component\Form\FormBuilderInterface; /** - * Interface for context for for document generation. + * Interface for context for document generation. */ interface DocGeneratorContextInterface { @@ -24,28 +25,37 @@ interface DocGeneratorContextInterface * * @param mixed $entity */ - public function getData($entity): array; + public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array; /** * Generate the form that display. * * @param mixed $entity */ - public function getForm($entity); + public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void; public static function getKey(): string; public function getName(): string; + public function getDescription(): string; + /** * has form. + * + * @param mixed $entity */ - public function hasForm(): bool; + public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool; - public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity): void; + public function hasAdminForm(): bool; - /** - * True of false which entity supports. - */ - public function supports(string $entityClass): bool; + public function buildAdminForm(FormBuilderInterface $builder): void; + + public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void; + + public function getEntityClass(): string; + + public function adminFormTransform(array $data): array; + + public function adminFormReverseTransform(array $data): array; } diff --git a/src/Bundle/ChillDocGeneratorBundle/Context/HouseholdMemberSelectionContext.php b/src/Bundle/ChillDocGeneratorBundle/Context/HouseholdMemberSelectionContext.php index a9734d9cf..2197995a0 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Context/HouseholdMemberSelectionContext.php +++ b/src/Bundle/ChillDocGeneratorBundle/Context/HouseholdMemberSelectionContext.php @@ -25,7 +25,7 @@ use function get_class; /** * Context that display a form to select a member of a houseHold. */ -class HouseholdMemberSelectionContext implements DocGeneratorContextInterface +class HouseholdMemberSelectionContext //implements DocGeneratorContextInterface { private EntityManagerInterface $em; diff --git a/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php b/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php index a7d24f127..aa0e34476 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php +++ b/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php @@ -11,8 +11,55 @@ declare(strict_types=1); namespace Chill\DocGeneratorBundle\Controller; +use Chill\DocGeneratorBundle\Context\ContextManager; +use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; use Chill\MainBundle\CRUD\Controller\CRUDController; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; class AdminDocGeneratorTemplateController extends CRUDController { + private ContextManager $contextManager; + + public function __construct(ContextManager $contextManager) + { + $this->contextManager = $contextManager; + } + + public function new(Request $request): Response + { + if (!$request->query->has('context')) { + return $this->redirectToRoute("chill_docgen_admin_template_pick-context"); + } + + return parent::new($request); + } + + protected function createEntity(string $action, Request $request): object + { + /** @var DocGeneratorTemplate $entity */ + $entity = parent::createEntity($action, $request); + $key = $request->query->get('context'); + $context = $this->contextManager->getContextByKey($key); + + $entity->setContext($key)->setEntity($context->getEntityClass()); + + return $entity; + } + + /** + * @Route("{_locale}/admin/docgen/template/pick-context", name="chill_docgen_admin_template_pick-context") + * @param Request $request + * @return Response + */ + public function pickContext(Request $request): Response + { + $this->denyAccessUnlessGranted('ROLE_ADMIN'); + + return $this->render('ChillDocGeneratorBundle:Admin/DocGeneratorTemplate:pick-context.html.twig', [ + 'contexts' => $this->contextManager->getContexts() + ]); + } + } diff --git a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php index 2a048d421..493bcb92e 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php +++ b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php @@ -30,6 +30,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; // TODO à mettre dans services +use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Routing\Annotation\Route; @@ -83,6 +84,35 @@ final class DocGeneratorTemplateController extends AbstractController int $entityId, Request $request ): Response { + $entity = $this->getDoctrine()->getRepository($entityClassName)->find($entityId); + + if (null === $entity) { + throw new NotFoundHttpException("Entity with classname $entityClassName and id $entityId is not found"); + } + + try { + $context = $this->contextManager->getContextByDocGeneratorTemplate($template); + } catch (ContextNotFoundException $e) { + throw new NotFoundHttpException($e->getMessage(), $e); + } + + if ($context->hasPublicForm($template, $entity)) { + $builder = $this->createFormBuilder(); + $context->buildPublicForm($builder, $template, $entity); + $form = $builder->getForm()->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $contextGenerationData = $form->getData(); + } elseif (!$form->isSubmitted() || ($form->isSubmitted() && !$form->isValid())) { + $template = '@ChillDocGenerator/Generator/basic_form.html.twig'; + $templateOptions = ['entity' => $entity, 'form' => $form->createView(), 'template' => $template]; + + return $this->render($template, $templateOptions); + } + } else { + $contextGenerationData = []; + } + $getUrlGen = $this->tempUrlGenerator->generate( 'GET', $template->getFile()->getFilename() @@ -107,30 +137,22 @@ final class DocGeneratorTemplateController extends AbstractController $tmpfnameDeCrypted = tempnam($this->kernel->getCacheDir(), 'DECRYPT_DOC_TEMPLATE'); // plus ou moins if (!$handle = fopen($tmpfnameDeCrypted, 'ab')) { - echo "Cannot open file ({$tmpfnameDeCrypted})"; + $this->logger->error("Cannot open file ({$tmpfnameDeCrypted})"); - exit; + throw new HttpException(500); } if (false === $ftemplate = fwrite($handle, $dataDecrypted)) { - echo "Cannot write to file ({$tmpfnameDeCrypted})"; + $this->logger->error("Cannot write to file ({$tmpfnameDeCrypted})"); - exit; + throw new HttpException(500); } dump("Success, wrote (to file ({$tmpfnameDeCrypted})"); fclose($handle); - $entity = $this->getDoctrine()->getRepository($entityClassName)->find($entityId); - - try { - $context = $this->contextManager->getContextByDocGeneratorTemplate($template); - } catch (ContextNotFoundException $e) { - throw new NotFoundHttpException($e->getMessage(), $e); - } - - $datas = $context->getData($entity); + $datas = $context->getData($template, $entity, $contextGenerationData); dump('process the data', $datas); @@ -182,7 +204,7 @@ final class DocGeneratorTemplateController extends AbstractController $em->persist($storedObject); try { - $context->storeGenerated($template, $storedObject, $entity); + $context->storeGenerated($template, $storedObject, $entity, $contextGenerationData); } catch (\Exception $e) { $this->logger->error('Could not store the associated document to entity', [ 'entityClassName' => $entityClassName, diff --git a/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php b/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php index 93be974ad..61e604757 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php +++ b/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php @@ -24,6 +24,11 @@ use Symfony\Component\Serializer\Annotation as Serializer; */ class DocGeneratorTemplate { + /** + * @ORM\Column(type="boolean", options={"default":true}) + */ + private bool $active = true; + /** * Class name of the context to use. * @@ -38,20 +43,24 @@ class DocGeneratorTemplate * @ORM\Column(type="text", nullable=true) * @Serializer\Groups({"read"}) */ - private string $description; + private ?string $description = null; /** - * Class name of the entities for which this template can be used. + * Class name of the entity for which this template can be used. * - * so if $entities = ['Chill\PersonBundle\Entity\AccompanyingPeriod', 'Chill\PersonBundle\Entity\SocialWork\SocialAction'] - * this template can be selected for an AccompanyingPeriod or a SocialAction - * - * @ORM\Column(type="simple_array") + * @ORM\Column(type="string", options={"default":""}) */ - private array $entities = []; + private string $entity = ""; /** - * @ORM\ManyToOne(targetEntity=StoredObject::class, cascade={"persist"}).) + * Options for the template + * + * @ORM\Column(type="json", name="template_options", options={"default":"[]"}) + */ + private array $options = []; + + /** + * @ORM\ManyToOne(targetEntity=StoredObject::class, cascade={"persist"})) */ private ?StoredObject $file = null; @@ -69,6 +78,18 @@ class DocGeneratorTemplate */ private array $name = []; + public function isActive(): bool + { + return $this->active; + } + + public function setActive(bool $active): DocGeneratorTemplate + { + $this->active = $active; + + return $this; + } + public function getContext(): ?string { return $this->context; @@ -79,11 +100,6 @@ class DocGeneratorTemplate return $this->description; } - public function getEntities(): ?array - { - return $this->entities; - } - public function getFile(): ?StoredObject { return $this->file; @@ -113,13 +129,6 @@ class DocGeneratorTemplate return $this; } - public function setEntities(array $entities): self - { - $this->entities = $entities; - - return $this; - } - public function setFile(StoredObject $file): self { $this->file = $file; @@ -133,4 +142,28 @@ class DocGeneratorTemplate return $this; } + + public function getEntity(): string + { + return $this->entity; + } + + public function setEntity(string $entity): self + { + $this->entity = $entity; + + return $this; + } + + public function getOptions(): array + { + return $this->options; + } + + public function setOptions(array $options): self + { + $this->options = $options; + + return $this; + } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php b/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php index e661c6d9e..474ac0571 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php +++ b/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php @@ -18,6 +18,7 @@ use Chill\DocStoreBundle\Form\StoredObjectType; use Chill\MainBundle\Form\Type\TranslatableStringFormType; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -33,30 +34,34 @@ class DocGeneratorTemplateType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { - $contexts = array_flip(array_map(static function (DocGeneratorContextInterface $c) { - return $c->getName(); - }, $this->contextManager->getContexts())); + /** @var DocGeneratorTemplate $template */ + $template = $options['data']; + $context = $this->contextManager->getContextByKey($template->getContext()); $builder ->add('name', TranslatableStringFormType::class, [ 'label' => 'Nom', ]) - ->add('context', ChoiceType::class, [ - 'required' => true, - 'label' => 'Context', - 'choices' => $contexts, - ]) - ->add('entities', ChoiceType::class, [ - 'multiple' => true, - 'choices' => [ - 'AccompanyingPeriod' => 'Chill\PersonBundle\Entity\AccompanyingPeriod', - 'SocialWork\SocialAction' => 'Chill\PersonBundle\Entity\SocialWork\SocialAction', - 'AccompanyingPeriod\AccompanyingPeriodWorkEvaluation' => AccompanyingPeriodWorkEvaluation::class, - ], ]) ->add('description') ->add('file', StoredObjectType::class, [ 'error_bubbling' => true, - ]); + ]) + ; + + if ($context->hasAdminForm()) { + $sub = $builder + ->create('options', null, ['compound' => true]) + ->addModelTransformer(new CallbackTransformer( + function (array $data) use ($context) { + return $context->adminFormTransform($data); + }, + function (array $data) use ($context) { + return $context->adminFormReverseTransform($data); + } + )); + $context->buildAdminForm($sub); + $builder->add($sub); + } } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php b/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php index 007f2fabb..5d99efa94 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php +++ b/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php @@ -31,8 +31,8 @@ final class DocGeneratorTemplateRepository implements ObjectRepository $builder ->select('count(t)') - ->where('t.entities LIKE :entity') - ->setParameter('entity', '%' . addslashes($entity) . '%'); + ->where('t.entity LIKE :entity') + ->setParameter('entity', addslashes($entity)); return $builder->getQuery()->getSingleScalarResult(); } @@ -69,8 +69,8 @@ final class DocGeneratorTemplateRepository implements ObjectRepository $builder = $this->repository->createQueryBuilder('t'); $builder - ->where('t.entities LIKE :entity') - ->setParameter('entity', '%' . addslashes($entity) . '%'); + ->where('t.entity LIKE :entity') + ->setParameter('entity', addslashes($entity)); return $builder ->getQuery() diff --git a/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/pick-context.html.twig b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/pick-context.html.twig new file mode 100644 index 000000000..d43e88f8d --- /dev/null +++ b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/pick-context.html.twig @@ -0,0 +1,27 @@ +{% extends '@ChillDocGenerator/Admin/layout.html.twig' %} + +{% block title 'Pick template context'|trans %} + +{% block layout_wvm_content %} +