diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php index 85e1c86b6..d58972a93 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php @@ -159,7 +159,9 @@ class HouseholdMemberController extends ApiController { // TODO ACL - $form = $this->createForm(HouseholdMemberType::class, $member); + $form = $this->createForm(HouseholdMemberType::class, $member, [ + 'validation_groups' => [ 'household_memberships' ] + ]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php index 349083fcb..1036481b7 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php @@ -19,7 +19,7 @@ use Chill\PersonBundle\Validator\Constraints\Household\MaxHolder; * @Serializer\DiscriminatorMap(typeProperty="type", mapping={ * "household"=Household::class * }) - * @MaxHolder(groups={"memberships"}) + * @MaxHolder(groups={"household_memberships"}) */ class Household { diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php index b891bbc15..611a9e84f 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php @@ -7,6 +7,7 @@ use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Household\Position; use Symfony\Component\Serializer\Annotation as Serializer; +use Symfony\Component\Validator\Constraints as Assert; /** @@ -28,18 +29,25 @@ class HouseholdMember /** * @ORM\ManyToOne(targetEntity=Position::class) * @Serializer\Groups({"read"}) + * @Assert\NotNull(groups={"household_memberships"}) */ private ?Position $position = null; /** * @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @Serializer\Groups({"read"}) + * @Assert\NotNull(groups={"household_memberships"}) */ private ?\DateTimeImmutable $startDate = null; /** * @ORM\Column(type="date_immutable", nullable= true, options={"default": null}) * @Serializer\Groups({"read"}) + * @Assert\GreaterThan( + * propertyPath="startDate", + * message="household_membership.The end date must be after start date", + * groups={"household_memberships"} + * ) */ private ?\DateTimeImmutable $endDate = null; @@ -67,6 +75,8 @@ class HouseholdMember * targetEntity="\Chill\PersonBundle\Entity\Person" * ) * @Serializer\Groups({"read"}) + * @Assert\Valid(groups={"household_memberships"}) + * @Assert\NotNull(groups={"household_memberships"}) */ private ?Person $person = null; @@ -76,6 +86,8 @@ class HouseholdMember * @ORM\ManyToOne( * targetEntity="\Chill\PersonBundle\Entity\Household\Household" * ) + * @Assert\Valid(groups={"household_memberships"}) + * @Assert\NotNull(groups={"household_memberships"}) */ private ?Household $household = null; diff --git a/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php b/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php index 44b364c56..4d8d5a165 100644 --- a/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php +++ b/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php @@ -35,7 +35,8 @@ class HouseholdMemberType extends AbstractType } $builder ->add('comment', ChillTextareaType::class, [ - 'label' => 'household.Comment' + 'label' => 'household.Comment', + 'required' => false ]) ; } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/HouseholdMembershipSequential.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/HouseholdMembershipSequential.php new file mode 100644 index 000000000..00d9e3306 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/HouseholdMembershipSequential.php @@ -0,0 +1,18 @@ +render = $render; + } + + public function validate($person, Constraint $constraint) + { + if (!$person instanceof Person) { + throw new UnexpectedTypeException($constraint, Person::class); + } + + $participations = $person->getHouseholdParticipations(); + + if ($participations->count() === 0) { + return; + } + + $covers = new DateRangeCovering(1, $participations[0] + ->getStartDate()->getTimezone()); + + foreach ($participations as $k => $p) { + $covers->add($p->getStartDate(), $p->getEndDate(), $k); + } + + $covers->compute(); + + if ($covers->hasIntersections()) { + foreach ($covers->getIntersections() as list($start, $end, $metadata)) { + $participation = $participations[$metadata[0]]; + + $this->context + ->buildViolation("household_membership.Person with membership covering") + ->setParameters([ + '%person_name%' => $this->render->renderString( + $participation->getPerson(), [] + ), + // TODO when date is correctly i18n, fix this + '%from%' => $start->format('d-m-Y') + ]) + ->addViolation() + ; + } + } + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services.yaml b/src/Bundle/ChillPersonBundle/config/services.yaml index 0f7ef3e1c..099b1d77c 100644 --- a/src/Bundle/ChillPersonBundle/config/services.yaml +++ b/src/Bundle/ChillPersonBundle/config/services.yaml @@ -57,6 +57,11 @@ services: tags: - { name: validator.constraint_validator, alias: birthdate_not_before } + Chill\PersonBundle\Validator\Constraints\Household\HouseholdMembershipSequentialValidator: + autowire: true + tags: + - { name: validator.constraint_validator } + Chill\PersonBundle\Repository\: autowire: true autoconfigure: true diff --git a/src/Bundle/ChillPersonBundle/config/validation.yaml b/src/Bundle/ChillPersonBundle/config/validation.yaml index b9041ddb9..fb0dd7b50 100644 --- a/src/Bundle/ChillPersonBundle/config/validation.yaml +++ b/src/Bundle/ChillPersonBundle/config/validation.yaml @@ -61,6 +61,9 @@ Chill\PersonBundle\Entity\Person: - Callback: callback: isAddressesValid groups: [addresses_consistent] + - Chill\PersonBundle\Validator\Constraints\Household\HouseholdMembershipSequential: + groups: [ 'household_memberships' ] + Chill\PersonBundle\Entity\AccompanyingPeriod: properties: diff --git a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml index 930494d58..82b5115d7 100644 --- a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml @@ -38,3 +38,6 @@ The date should not be empty: La date ne doit pas être vide household: max_holder_overflowed_infinity: Il ne peut pas y avoir plus de deux titulaires simultanément. Or, avec cette modification, ce nombre sera dépassé à partir du {{ start }}. max_holder_overflowed: Il ne peut y avoir plus de deux titulaires simultanément. Or, avec cette modification, ce nombre sera dépassé entre le {{ start }} et le {{ end }}. +household_membership: + The end date must be after start date: La date de la fin de l'appartenance doit être postérieure à la date de début. + Person with membership covering: Une personne ne peut pas appartenir à deux ménages simultanément. Or, avec cette modification, %person_name% appartiendrait à deux ménages à partir du %from%.