From de4e83b3fb25103e4f4f55e42adc15674526698b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 30 Nov 2021 23:23:02 +0100 Subject: [PATCH] Generate a context for docgen, on accompanying period --- .../ChillDocGeneratorBundle.php | 1 - .../Context/ContextManager.php | 12 +- .../Context/DocGeneratorContextInterface.php | 9 +- .../Exception/UnexpectedTypeException.php | 18 ++- .../HouseholdMemberSelectionContext.php | 20 +-- .../DocGeneratorTemplateController.php | 38 ++--- .../ORM/LoadDocGeneratorTemplate.php | 9 +- .../Entity/DocGeneratorTemplate.php | 6 +- .../Form/DocGeneratorTemplateType.php | 19 ++- .../migrations/Version20211103111010.php | 29 ++-- .../Resolver/ScopeResolverDispatcher.php | 9 +- .../Templating/TranslatableStringHelper.php | 12 +- .../Controller/HouseholdMemberController.php | 2 +- .../Entity/AccompanyingPeriod.php | 74 +++++---- .../Entity/AccompanyingPeriod/Origin.php | 10 +- .../AccompanyingPeriodDocGenNormalizer.php | 147 ++++++++++++++++++ .../AccompanyingPeriodContext.php | 32 ++-- ...AccompanyingPeriodDocGenNormalizerTest.php | 109 +++++++++++++ .../translations/messages.fr.yml | 5 + 19 files changed, 433 insertions(+), 128 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodDocGenNormalizer.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/AccompanyingPeriodDocGenNormalizerTest.php diff --git a/src/Bundle/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php b/src/Bundle/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php index d85b1f7ee..aa02a6101 100644 --- a/src/Bundle/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php +++ b/src/Bundle/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php @@ -12,7 +12,6 @@ declare(strict_types=1); namespace Chill\DocGeneratorBundle; use Chill\DocGeneratorBundle\Context\DocGeneratorContextInterface; -use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; diff --git a/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php b/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php index ec065732c..a2eb3742c 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php +++ b/src/Bundle/ChillDocGeneratorBundle/Context/ContextManager.php @@ -1,14 +1,20 @@ contexts = $contexts; diff --git a/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php b/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php index df8c55042..7118b8eab 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php +++ b/src/Bundle/ChillDocGeneratorBundle/Context/DocGeneratorContextInterface.php @@ -16,11 +16,6 @@ namespace Chill\DocGeneratorBundle\Context; */ interface DocGeneratorContextInterface { - - public static function getKey(): string; - - public function getName(): string; - /** * Get the data that will be injected to the generated document. * @@ -35,6 +30,10 @@ interface DocGeneratorContextInterface */ public function getForm($entity); + public static function getKey(): string; + + public function getName(): string; + /** * has form. */ diff --git a/src/Bundle/ChillDocGeneratorBundle/Context/Exception/UnexpectedTypeException.php b/src/Bundle/ChillDocGeneratorBundle/Context/Exception/UnexpectedTypeException.php index 727c12050..617ec537a 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Context/Exception/UnexpectedTypeException.php +++ b/src/Bundle/ChillDocGeneratorBundle/Context/Exception/UnexpectedTypeException.php @@ -1,11 +1,25 @@ generate( 'GET', - $template->getFile()->getFilename()); + $template->getFile()->getFilename() + ); $data = $this->client->request('GET', $getUrlGen->url); @@ -92,23 +90,25 @@ final class DocGeneratorTemplateController extends AbstractController $dataDecrypted = openssl_decrypt($data->getContent(), $method, $keyGoodFormat, 1, $ivGoodFormat); - if ($dataDecrypted === FALSE) { - throw new \Exception("Error during Decrypt ", 1); + if (false === $dataDecrypted) { + throw new \Exception('Error during Decrypt ', 1); } $tmpfnameDeCrypted = tempnam($this->kernel->getCacheDir(), 'DECRYPT_DOC_TEMPLATE'); // plus ou moins - if (!$handle = fopen($tmpfnameDeCrypted, 'a')) { - echo "Cannot open file ($tmpfnameDeCrypted)"; + if (!$handle = fopen($tmpfnameDeCrypted, 'ab')) { + echo "Cannot open file ({$tmpfnameDeCrypted})"; + exit; } - if (fwrite($handle, $dataDecrypted) === FALSE) { - echo "Cannot write to file ($tmpfnameDeCrypted)"; + if (fwrite($handle, $dataDecrypted) === false) { + echo "Cannot write to file ({$tmpfnameDeCrypted})"; + exit; } - dump("Success, wrote ($dataDecrypted) to file ($tmpfnameDeCrypted)"); + dump("Success, wrote ({$dataDecrypted}) to file ({$tmpfnameDeCrypted})"); fclose($handle); @@ -185,7 +185,7 @@ final class DocGeneratorTemplateController extends AbstractController } throw new Exception('Unable to generate document.'); - } + } /** * @Route( diff --git a/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php b/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php index af8915df7..0db7bbd44 100644 --- a/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php +++ b/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php @@ -12,10 +12,11 @@ declare(strict_types=1); namespace Chill\DocGeneratorBundle\DataFixtures\ORM; use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; +use Chill\DocStoreBundle\Entity\StoredObject; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; +use DateTime; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Persistence\ObjectManager; -use Chill\DocStoreBundle\Entity\StoredObject; /** * Load DocGeneratorTemplate. @@ -32,7 +33,7 @@ class LoadDocGeneratorTemplate extends AbstractFixture 'filename' => 'pKNlhCrQDCRsAuC8vYHDKa', 'key' => '{"alg":"A256CBC","ext":true,"k":"_VihnD41-VDHlpS-ouwtbMPnu-OXVdtA7ENQWWtAQYM","key_ops":["encrypt","decrypt"],"kty":"oct"}', 'iv' => '[86,231,83,148,117,107,149,173,130,19,105,194,224,145,8,48]', - 'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' + 'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', ], 'context' => 'Chill\DocGeneratorBundle\Context\HouseholdMemberSelectionContext', 'entities' => [AccompanyingPeriodWorkEvaluation::class], @@ -43,7 +44,7 @@ class LoadDocGeneratorTemplate extends AbstractFixture 'filename' => 'pKNlhCrQDCRsAuC8vYHDKa', 'key' => '{"alg":"A256CBC","ext":true,"k":"_VihnD41-VDHlpS-ouwtbMPnu-OXVdtA7ENQWWtAQYM","key_ops":["encrypt","decrypt"],"kty":"oct"}', 'iv' => '[86,231,83,148,117,107,149,173,130,19,105,194,224,145,8,48]', - 'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' + 'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', ], 'context' => 'Chill\DocGeneratorBundle\Context\HouseholdMemberSelectionContext', 'entities' => ['Chill\PersonBundle\Entity\AccompanyingPeriod', 'Chill\PersonBundle\Entity\SocialWork\SocialAction', AccompanyingPeriodWorkEvaluation::class], @@ -57,7 +58,7 @@ class LoadDocGeneratorTemplate extends AbstractFixture ->setFilename($template['file']['filename']) ->setKeyInfos(json_decode($template['file']['key'], true)) ->setIv(json_decode($template['file']['iv'], true)) - ->setCreationDate(new \DateTime('today')) + ->setCreationDate(new DateTime('today')) ->setType($template['file']['type']); $manager->persist($newStoredObj); diff --git a/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php b/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php index 751fd75cb..93be974ad 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php +++ b/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php @@ -11,9 +11,9 @@ declare(strict_types=1); namespace Chill\DocGeneratorBundle\Entity; +use Chill\DocStoreBundle\Entity\StoredObject; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation as Serializer; -use Chill\DocStoreBundle\Entity\StoredObject; /** * @ORM\Entity @@ -62,7 +62,6 @@ class DocGeneratorTemplate * @Serializer\Groups({"read"}) */ private int $id; - /** * @ORM\Column(type="json") @@ -95,11 +94,10 @@ class DocGeneratorTemplate return $this->id; } - public function getName(): ?array + public function getName(): ?array { return $this->name; } - public function setContext(string $context): self { diff --git a/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php b/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php index 4ffbbd1e3..f453ffa35 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php +++ b/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php @@ -14,13 +14,13 @@ namespace Chill\DocGeneratorBundle\Form; use Chill\DocGeneratorBundle\Context\ContextManager; use Chill\DocGeneratorBundle\Context\DocGeneratorContextInterface; use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate; +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\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\DocStoreBundle\Form\StoredObjectType; -use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; class DocGeneratorTemplateType extends AbstractType { @@ -33,7 +33,7 @@ class DocGeneratorTemplateType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { - $contexts = \array_flip(\array_map(function (DocGeneratorContextInterface $c) { + $contexts = array_flip(array_map(static function (DocGeneratorContextInterface $c) { return $c->getName(); }, $this->contextManager->getContext())); @@ -44,20 +44,19 @@ class DocGeneratorTemplateType extends AbstractType ->add('context', ChoiceType::class, [ 'required' => true, 'label' => 'Context', - 'choices' => $contexts + 'choices' => $contexts, ]) ->add('entities', ChoiceType::class, [ 'multiple' => true, - 'choices' => [ + 'choices' => [ 'AccompanyingPeriod' => 'Chill\PersonBundle\Entity\AccompanyingPeriod', 'SocialWork\SocialAction' => 'Chill\PersonBundle\Entity\SocialWork\SocialAction', - 'AccompanyingPeriod\AccompanyingPeriodWorkEvaluation' => AccompanyingPeriodWorkEvaluation::class - ]]) + 'AccompanyingPeriod\AccompanyingPeriodWorkEvaluation' => AccompanyingPeriodWorkEvaluation::class, + ], ]) ->add('description') ->add('file', StoredObjectType::class, [ - 'error_bubbling' => true - ]) - ; + 'error_bubbling' => true, + ]); } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211103111010.php b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211103111010.php index f3f6b32d0..1530fd065 100644 --- a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211103111010.php +++ b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211103111010.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_docgen_template DROP CONSTRAINT FK_49A347E893CB796C'); + $this->addSql('DROP INDEX IDX_49A347E893CB796C'); + $this->addSql('ALTER TABLE chill_docgen_template ADD file VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE chill_docgen_template DROP file_id'); + $this->addSql('ALTER TABLE chill_docgen_template ALTER entities DROP NOT NULL'); + $this->addSql('ALTER TABLE chill_docgen_template ALTER context DROP NOT NULL'); + } + public function getDescription(): string { return 'Using DocStore objects inside the DocGenTemplate'; @@ -26,14 +43,4 @@ final class Version20211103111010 extends AbstractMigration $this->addSql('ALTER TABLE chill_docgen_template ADD CONSTRAINT FK_49A347E893CB796C FOREIGN KEY (file_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_49A347E893CB796C ON chill_docgen_template (file_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_docgen_template DROP CONSTRAINT FK_49A347E893CB796C'); - $this->addSql('DROP INDEX IDX_49A347E893CB796C'); - $this->addSql('ALTER TABLE chill_docgen_template ADD file VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE chill_docgen_template DROP file_id'); - $this->addSql('ALTER TABLE chill_docgen_template ALTER entities DROP NOT NULL'); - $this->addSql('ALTER TABLE chill_docgen_template ALTER context DROP NOT NULL'); - } } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php b/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php index 1cd03e2b7..0e4cfdc78 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Security\Resolver; use Chill\MainBundle\Entity\Scope; +use Doctrine\Common\Collections\Collection; final class ScopeResolverDispatcher { @@ -45,7 +46,13 @@ final class ScopeResolverDispatcher { foreach ($this->resolvers as $resolver) { if ($resolver->supports($entity, $options)) { - return $resolver->resolveScope($entity, $options); + $scopes = $resolver->resolveScope($entity, $options); + + if ($scopes instanceof Collection) { + return $scopes->toArray(); + } + + return $scopes; } } diff --git a/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php index 5da53f515..e354fe9f0 100644 --- a/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Templating; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Contracts\Translation\TranslatorInterface; use function array_key_exists; @@ -21,10 +22,13 @@ final class TranslatableStringHelper implements TranslatableStringHelperInterfac private TranslatorInterface $translator; - public function __construct(RequestStack $requestStack, TranslatorInterface $translator) + private string $defaultLocale; + + public function __construct(RequestStack $requestStack, TranslatorInterface $translator, ParameterBagInterface $parameterBag) { $this->requestStack = $requestStack; $this->translator = $translator; + $this->defaultLocale = $parameterBag->get('kernel.default_locale'); } public function localize(array $translatableStrings): ?string @@ -35,11 +39,7 @@ final class TranslatableStringHelper implements TranslatableStringHelperInterfac $request = $this->requestStack->getCurrentRequest(); - if (null === $request) { - return null; - } - - $language = $request->getLocale(); + $language = null === $request ? $this->defaultLocale : $request->getLocale(); if (array_key_exists($language, $translatableStrings)) { return $translatableStrings[$language]; diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php index 802f9fd6c..012d0fd68 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php @@ -186,7 +186,7 @@ class HouseholdMemberController extends ApiController $_format, ['groups' => ['read']] ); - } catch (Exception\InvalidArgumentException|Exception\UnexpectedValueException $e) { + } catch (Exception\InvalidArgumentException | Exception\UnexpectedValueException $e) { throw new BadRequestException("Deserialization error: {$e->getMessage()}", 45896, $e); } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 13109cc98..d3595932c 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -117,11 +117,11 @@ class AccompanyingPeriod implements * @var DateTime * * @ORM\Column(type="date", nullable=true) - * @Groups({"read", "write"}) + * @Groups({"read", "write", "docgen:read"}) * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CLOSED}) * @Assert\GreaterThan(propertyPath="openingDate", groups={AccompanyingPeriod::STEP_CLOSED}) */ - private $closingDate; + private ?DateTime $closingDate = null; /** * @var AccompanyingPeriod\ClosingMotive @@ -132,7 +132,7 @@ class AccompanyingPeriod implements * @Groups({"read", "write"}) * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CLOSED}) */ - private $closingMotive; + private ?ClosingMotive $closingMotive = null; /** * @var Collection @@ -144,33 +144,34 @@ class AccompanyingPeriod implements * ) * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_DRAFT}) */ - private $comments; + private Collection $comments; /** * @var bool * @ORM\Column(type="boolean", options={"default": false}) - * @Groups({"read", "write"}) + * @Groups({"read", "write", "docgen:read"}) */ - private $confidential = false; + private bool $confidential = false; /** * @ORM\Column(type="datetime", nullable=true, options={"default": NULL}) + * @Groups({"docgen:read"}) */ - private DateTimeInterface $createdAt; + private ?DateTimeInterface $createdAt = null; /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(nullable=true) - * @Groups({"read"}) + * @Groups({"read", "docgen:read"}) */ - private $createdBy; + private ?User $createdBy = null; /** * @var bool * @ORM\Column(type="boolean", options={"default": false}) - * @Groups({"read", "write"}) + * @Groups({"read", "write", "docgen:read"}) */ - private $emergency = false; + private bool $emergency = false; /** * @var int @@ -178,9 +179,9 @@ class AccompanyingPeriod implements * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") - * @Groups({"read"}) + * @Groups({"read", "docgen:read"}) */ - private $id; + private ?int $id = null; /** * @ORM\ManyToOne( @@ -202,9 +203,9 @@ class AccompanyingPeriod implements * @var DateTime * * @ORM\Column(type="date") - * @Groups({"read", "write"}) + * @Groups({"read", "write", "docgen:read"}) */ - private $openingDate; + private ?DateTime $openingDate = null; /** * @ORM\ManyToOne(targetEntity=Origin::class) @@ -212,7 +213,7 @@ class AccompanyingPeriod implements * @Groups({"read", "write"}) * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED}) */ - private $origin; + private ?Origin $origin = null; /** * @var Collection @@ -220,10 +221,10 @@ class AccompanyingPeriod implements * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class, * mappedBy="accompanyingPeriod", orphanRemoval=true, * cascade={"persist", "refresh", "remove", "merge", "detach"}) - * @Groups({"read"}) + * @Groups({"read", "docgen:read"}) * @ParticipationOverlap(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED}) */ - private $participations; + private Collection $participations; /** * @ORM\ManyToOne( @@ -239,26 +240,26 @@ class AccompanyingPeriod implements * @ORM\Column(type="text") * @Groups({"read", "write"}) */ - private $remark = ''; + private string $remark = ''; /** * @var bool * @ORM\Column(type="boolean", options={"default": false}) - * @Groups({"read", "write"}) + * @Groups({"read", "write", "docgen:read"}) */ - private $requestorAnonymous = false; + private bool $requestorAnonymous = false; /** * @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodRequested") * @ORM\JoinColumn(nullable=true) */ - private $requestorPerson; + private ?Person $requestorPerson = null; /** * @ORM\ManyToOne(targetEntity=ThirdParty::class) * @ORM\JoinColumn(nullable=true) */ - private $requestorThirdParty; + private ?ThirdParty $requestorThirdParty = null; /** * @var Collection @@ -272,7 +273,7 @@ class AccompanyingPeriod implements * @Groups({"read"}) * @ResourceDuplicateCheck(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED, "Default", "default"}) */ - private $resources; + private Collection $resources; /** * @var Collection @@ -288,7 +289,7 @@ class AccompanyingPeriod implements * @Groups({"read"}) * @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}, minMessage="A course must be associated to at least one scope") */ - private $scopes; + private Collection $scopes; /** * @ORM\ManyToMany( @@ -297,7 +298,7 @@ class AccompanyingPeriod implements * @ORM\JoinTable( * name="chill_person_accompanying_period_social_issues" * ) - * @Groups({"read"}) + * @Groups({"read", "docgen:read"}) * @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}, minMessage="A course must contains at least one social issue") */ private Collection $socialIssues; @@ -307,26 +308,26 @@ class AccompanyingPeriod implements * @ORM\Column(type="string", length=32, nullable=true) * @Groups({"read"}) */ - private $step = self::STEP_DRAFT; + private string $step = self::STEP_DRAFT; /** * @ORM\Column(type="datetime", nullable=true, options={"default": NULL}) */ - private DateTimeInterface $updatedAt; + private ?DateTimeInterface $updatedAt = null; /** * @ORM\ManyToOne( * targetEntity=User::class * ) */ - private User $updatedBy; + private ?User $updatedBy = null; /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(nullable=true) - * @Groups({"read", "write"}) + * @Groups({"read", "write", "docgen:read"}) */ - private $user; + private ?User $user = null; /** * @ORM\OneToMany( @@ -577,6 +578,11 @@ class AccompanyingPeriod implements }); } + public function getCreatedAt(): ?DateTime + { + return $this->createdAt; + } + public function getCreatedBy(): ?User { return $this->createdBy; @@ -605,7 +611,7 @@ class AccompanyingPeriod implements * * @return int */ - public function getId() + public function getId(): ?int { return $this->id; } @@ -631,7 +637,7 @@ class AccompanyingPeriod implements public function getLocation(?DateTimeImmutable $at = null): ?Address { if ($this->getPersonLocation() instanceof Person) { - return $this->getPersonLocation()->getCurrentHouseholdAddress($at); + return $this->getPersonLocation()->getCurrentPersonAddress(); } return $this->getAddressLocation(); @@ -660,7 +666,7 @@ class AccompanyingPeriod implements * * @return DateTime */ - public function getOpeningDate() + public function getOpeningDate(): ?\DateTime { return $this->openingDate; } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php index 7d35b8684..09ebc7d31 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php @@ -33,26 +33,26 @@ class Origin * @ORM\Column(type="integer") * @Groups({"read"}) */ - private $id; + private ?int $id = null; /** * @ORM\Column(type="json") * @Groups({"read"}) */ - private $label; + private array $label = []; /** * @ORM\Column(type="date_immutable", nullable=true) * @Groups({"read"}) */ - private $noActiveAfter; + private ?\DateTimeImmutable $noActiveAfter = null; public function getId(): ?int { return $this->id; } - public function getLabel() + public function getLabel(): array { return $this->label; } @@ -62,7 +62,7 @@ class Origin return $this->noActiveAfter; } - public function setLabel(string $label): self + public function setLabel(array $label): self { $this->label = $label; diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodDocGenNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodDocGenNormalizer.php new file mode 100644 index 000000000..d3243c48b --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodDocGenNormalizer.php @@ -0,0 +1,147 @@ + "", + 'closingDate' => \DateTime::class, + 'confidential' => "", + 'confidentialText' => '', + 'createdAt' => \DateTime::class, + 'createdBy' => User::class, + 'emergency' => "", + 'emergencyText' => '', + 'openingDate' => \DateTime::class, + 'originText' => '', + 'requestorAnonymous' => false, + 'socialIssues' => [], + 'intensity' => '', + 'step' => '', + 'closingMotiveText' => '', + 'socialIssuesText' => '', + 'scopes' => [], + 'scopesText' => '', + 'ref' => User::class, + 'participations' => [], + ]; + + public function __construct( + TranslatorInterface $translator, + TranslatableStringHelper $translatableStringHelper, + SocialIssueRender $socialIssueRender, + ClosingMotiveRender $closingMotiveRender, + ScopeResolverDispatcher $scopeResolverDispatcher + ) { + $this->translator = $translator; + $this->translatableStringHelper = $translatableStringHelper; + $this->socialIssueRender = $socialIssueRender; + $this->closingMotiveRender = $closingMotiveRender; + $this->scopeResolverDispatcher = $scopeResolverDispatcher; + } + + + public function supportsNormalization($data, string $format = null, array $context = []): bool + { + if ('docgen' !== $format) { + return false; + } + + if ($data instanceof AccompanyingPeriod) { + if (array_key_exists(self::IGNORE_FIRST_PASS_KEY, $context) + && in_array(spl_object_hash($data), $context[self::IGNORE_FIRST_PASS_KEY])) { + return false; + } + + return true; + } elseif (null === $data && ($context['docgen:expects'] ?? null) === AccompanyingPeriod::class) { + return true; + } + + return false; + } + + /** + * @param AccompanyingPeriod|null $period + */ + public function normalize($period, string $format = null, array $context = []) + { + if ($period instanceof AccompanyingPeriod) { + $ignored = $context[self::IGNORE_FIRST_PASS_KEY] ?? []; + $ignored[] = spl_object_hash($period); + $initial = + $this->normalizer->normalize($period, $format, \array_merge($context, + [self::IGNORE_FIRST_PASS_KEY => $ignored, AbstractNormalizer::GROUPS => 'docgen:read'])); + + // some transformation + $user = $initial['user']; + unset($initial['user']); + + $scopes = $this->scopeResolverDispatcher->isConcerned($period) ? $this->scopeResolverDispatcher->resolveScope($period) : []; + + if (!is_array($scopes)) { + $scopes = [$scopes]; + } + + return array_merge( + // get a first default data + $initial, + // and add data custom + [ + 'intensity' => $this->translator->trans($period->getIntensity()), + 'step' => $this->translator->trans('accompanying_period.'.$period->getStep()), + 'emergencyText' => $period->isEmergency() ? $this->translator->trans('accompanying_period.emergency') : '', + 'confidentialText' => $period->isConfidential() ? $this->translator->trans('confidential') : '', + 'originText' => null !== $period->getOrigin() ? $this->translatableStringHelper->localize($period->getOrigin()->getLabel()) : '', + 'closingMotiveText' => null !== $period->getClosingMotive() ? + $this->closingMotiveRender->renderString($period->getClosingMotive(), []) : '', + 'ref' => $user, + 'socialIssuesText' => implode(', ', array_map(function(SocialIssue $s) { + return $this->socialIssueRender->renderString($s, []); + }, $period->getSocialIssues()->toArray())), + 'scopesText' => implode(', ', array_map(function (Scope $s) { + return $this->translatableStringHelper->localize($s->getName()); + }, $scopes)), + 'scopes' => $scopes, + ] + ); + } elseif (null === $period) { + return self::PERIOD_NULL; + } + + throw new InvalidArgumentException("this neither an accompanying period or null"); + } +} diff --git a/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php b/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php index 2f286351e..2a3fb10f4 100644 --- a/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php +++ b/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php @@ -1,10 +1,18 @@ normalizer = self::$container->get(NormalizerInterface::class); + } + + public function testNormalize() + { + $period = new AccompanyingPeriod(); + $period->setConfidential(true); + $period->setEmergency(true); + $period->setOrigin((new AccompanyingPeriod\Origin())->setLabel(['fr' => 'origin'])); + $period->setClosingMotive((new AccompanyingPeriod\ClosingMotive())->setName(['closing'])); + $period->addScope((new Scope())->setName(['fr' => 'scope1'])); + $period->addScope((new Scope())->setName(['fr' =>'scope2'])); + $period->addSocialIssue((new SocialIssue())->setTitle(['fr' => 'issue1'])); + $period->addSocialIssue((new SocialIssue())->setTitle(['fr' => 'issue2'])); + $data = $this->normalizer->normalize($period, 'docgen', ['docgen:expects' => AccompanyingPeriod::class]); + + $expected = [ + 'id' => null, + 'closingDate' => '@ignored', + 'confidential' => true, + 'confidentialText' => 'confidentiel', + 'createdAt' => '@ignored', + 'createdBy' => '@ignored', + 'emergency' => true, + 'emergencyText' => 'Urgent', + 'openingDate' => '@ignored', + 'originText' => 'origin', + 'requestorAnonymous' => false, + 'socialIssues' => '@ignored', + 'intensity' => 'ponctuel', + 'step' => 'Brouillon', + 'closingMotiveText' => 'closing', + 'socialIssuesText' => 'issue1, issue2', + 'scopes' => '@ignored', + 'scopesText' => 'scope1, scope2', + 'ref' => '@ignored', + 'participations' => '@ignored', + ]; + + $this->assertIsArray($data); + $this->assertEqualsCanonicalizing(array_keys($expected), array_keys($data)); + + foreach ($expected as $key => $item) { + if ($item === '@ignored') { + continue; + } + + $this->assertEquals($item, $data[$key]); + } + } + + public function testNormalizeNull() + { + $data = $this->normalizer->normalize(null, 'docgen', ['docgen:expects' => AccompanyingPeriod::class]); + + $expected = [ + 'id' => "", + 'closingDate' => '@ignored', + 'confidential' => "", + 'confidentialText' => '', + 'createdAt' => '@ignored', + 'createdBy' => '@ignored', + 'emergency' => "", + 'emergencyText' => '', + 'openingDate' => '@ignored', + 'originText' => '', + 'requestorAnonymous' => '', + 'socialIssues' => '@ignored', + 'intensity' => '', + 'step' => '', + 'closingMotiveText' => '', + 'socialIssuesText' => '', + 'scopes' => '@ignored', + 'scopesText' => '', + 'ref' => '@ignored', + 'participations' => '@ignored', + ]; + + $this->assertIsArray($data); + $this->assertEqualsCanonicalizing(array_keys($expected), array_keys($data)); + + foreach ($expected as $key => $item) { + if ($item === '@ignored') { + continue; + } + + $this->assertEquals($item, $data[$key]); + } + } + +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 46077fdf0..904ec8811 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -377,9 +377,14 @@ accompanying_period: dates: Période dates_from_%opening_date%: Ouvert depuis le %opening_date% dates_from_%opening_date%_to_%closing_date%: Ouvert du %opening_date% au %closing_date% + DRAFT: Brouillon + CONFIRMED: Confirmé + CLOSED: Clotûré + emergency: Urgent occasional: ponctuel regular: régulier Confidential: confidentiel +confidential: confidentiel Draft: brouillon Confirmed: en file active Closed: Cloturé