diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f22e6dd9..467ed8037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to ## Unreleased +* [activity] add custom validation on the Activity class, based on what is required from the ActivityType (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/188) * [main] translate multiselect messages when selecting/creating address * [main] set the coordinates of the city when creating a new address OR choosing "pas d'adresse complète" * Use the user.label in accompanying course banner, instead of username; diff --git a/phpstan-critical.neon b/phpstan-critical.neon index 6147f2022..b214654bf 100644 --- a/phpstan-critical.neon +++ b/phpstan-critical.neon @@ -70,11 +70,6 @@ parameters: count: 1 path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php - - - message: "#^Undefined variable\\: \\$value$#" - count: 1 - path: src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidityValidator.php - - message: "#^Undefined variable\\: \\$choiceSlug$#" count: 1 diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index 0c43c4d91..0f725c2b3 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -408,7 +408,7 @@ final class ActivityController extends AbstractController $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); - $defaultLocationId = $this->getUser()->getCurrentLocation()->getId(); + $defaultLocation = $this->getUser()->getCurrentLocation(); return $this->render($view, [ 'person' => $person, @@ -416,7 +416,7 @@ final class ActivityController extends AbstractController 'entity' => $entity, 'form' => $form->createView(), 'activity_json' => $activity_array, - 'default_location_id' => $defaultLocationId, + 'default_location' => $defaultLocation, ]); } diff --git a/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeController.php b/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeController.php index 140a0b855..81c978bf2 100644 --- a/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeController.php +++ b/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeController.php @@ -23,6 +23,7 @@ class AdminActivityTypeController extends CRUDController protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator) { /** @var \Doctrine\ORM\QueryBuilder $query */ - return $query->orderBy('e.ordering', 'ASC'); + return $query->orderBy('e.ordering', 'ASC') + ->addOrderBy('e.id', 'ASC'); } } diff --git a/src/Bundle/ChillActivityBundle/Entity/Activity.php b/src/Bundle/ChillActivityBundle/Entity/Activity.php index 85abed5e5..c63ce90f7 100644 --- a/src/Bundle/ChillActivityBundle/Entity/Activity.php +++ b/src/Bundle/ChillActivityBundle/Entity/Activity.php @@ -9,6 +9,7 @@ namespace Chill\ActivityBundle\Entity; +use Chill\ActivityBundle\Validator\Constraints as ActivityValidator; use Chill\DocStoreBundle\Entity\Document; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; @@ -41,6 +42,7 @@ use Symfony\Component\Serializer\Annotation\SerializedName; * @DiscriminatorMap(typeProperty="type", mapping={ * "activity": Activity::class * }) + * @ActivityValidator\ActivityValidity */ /* @@ -202,7 +204,9 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer public function addPerson(?Person $person): self { if (null !== $person) { - $this->persons[] = $person; + if (!$this->persons->contains($person)) { + $this->persons[] = $person; + } } return $this; @@ -236,7 +240,9 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer public function addThirdParty(?ThirdParty $thirdParty): self { if (null !== $thirdParty) { - $this->thirdParties[] = $thirdParty; + if (!$this->thirdParties->contains($thirdParty)) { + $this->thirdParties[] = $thirdParty; + } } return $this; @@ -245,7 +251,9 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer public function addUser(?User $user): self { if (null !== $user) { - $this->users[] = $user; + if (!$this->users->contains($user)) { + $this->users[] = $user; + } } return $this; diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php index 0e9b1150a..4cb4250b5 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php @@ -12,6 +12,7 @@ namespace Chill\ActivityBundle\Entity; use Doctrine\ORM\Mapping as ORM; use InvalidArgumentException; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints as Assert; /** * Class ActivityType. @@ -29,11 +30,13 @@ class ActivityType public const FIELD_REQUIRED = 2; /** + * @deprecated not in use * @ORM\Column(type="string", nullable=false, options={"default": ""}) */ private string $accompanyingPeriodLabel = ''; /** + * @deprecated not in use * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) */ private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE; @@ -195,16 +198,21 @@ class ActivityType /** * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + * @Assert\EqualTo(propertyPath="socialIssuesVisible", message="This parameter must be equal to social issue parameter") */ private int $socialActionsVisible = self::FIELD_INVISIBLE; /** * @ORM\Column(type="string", nullable=false, options={"default": ""}) + * + * @deprecated not in use */ private string $socialDataLabel = ''; /** * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + * + * @deprecated not in use */ private int $socialDataVisible = self::FIELD_INVISIBLE; @@ -260,16 +268,6 @@ class ActivityType */ private int $userVisible = self::FIELD_REQUIRED; - public function getAccompanyingPeriodLabel(): string - { - return $this->accompanyingPeriodLabel; - } - - public function getAccompanyingPeriodVisible(): int - { - return $this->accompanyingPeriodVisible; - } - /** * Get active * return true if the type is active. @@ -446,16 +444,6 @@ class ActivityType return $this->socialActionsVisible; } - public function getSocialDataLabel(): string - { - return $this->socialDataLabel; - } - - public function getSocialDataVisible(): int - { - return $this->socialDataVisible; - } - public function getSocialIssuesLabel(): ?string { return $this->socialIssuesLabel; @@ -537,20 +525,6 @@ class ActivityType return self::FIELD_INVISIBLE !== $this->{$property}; } - public function setAccompanyingPeriodLabel(string $accompanyingPeriodLabel): self - { - $this->accompanyingPeriodLabel = $accompanyingPeriodLabel; - - return $this; - } - - public function setAccompanyingPeriodVisible(int $accompanyingPeriodVisible): self - { - $this->accompanyingPeriodVisible = $accompanyingPeriodVisible; - - return $this; - } - /** * Set active * set to true if the type is active. @@ -768,20 +742,6 @@ class ActivityType return $this; } - public function setSocialDataLabel(string $socialDataLabel): self - { - $this->socialDataLabel = $socialDataLabel; - - return $this; - } - - public function setSocialDataVisible(int $socialDataVisible): self - { - $this->socialDataVisible = $socialDataVisible; - - return $this; - } - public function setSocialIssuesLabel(string $socialIssuesLabel): self { $this->socialIssuesLabel = $socialIssuesLabel; diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php index 300be5c4c..682d73aaf 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php @@ -56,7 +56,7 @@ class ActivityTypeType extends AbstractType 'persons', 'user', 'date', 'place', 'persons', 'thirdParties', 'durationTime', 'travelTime', 'attendee', 'reasons', 'comment', 'sentReceived', 'documents', - 'emergency', 'accompanyingPeriod', 'socialData', 'users', + 'emergency', 'socialIssues', 'socialActions', 'users', ]; foreach ($fields as $field) { diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/App.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/App.vue index 52454c2f7..2fb9d022d 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/App.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/App.vue @@ -1,7 +1,7 @@ {{ encore_entry_script_tags('vue_activity') }} {% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Validator/Constraints/ActivityValidity.php b/src/Bundle/ChillActivityBundle/Validator/Constraints/ActivityValidity.php new file mode 100644 index 000000000..6164c3c5d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Validator/Constraints/ActivityValidity.php @@ -0,0 +1,42 @@ +getActivityType()->getPersonsVisible() === 2 && count($activity->getPersons()) === 0) { + $this->context + ->buildViolation($constraint->noPersonsMessage) + ->addViolation(); + } + + if ($activity->getActivityType()->getUsersVisible() === 2 && count($activity->getUsers()) === 0) { + $this->context + ->buildViolation($constraint->noUsersMessage) + ->addViolation(); + } + + if ($activity->getActivityType()->getThirdPartiesVisible() === 2 && count($activity->getThirdParties()) === 0) { + $this->context + ->buildViolation($constraint->noThirdPartiesMessage) + ->addViolation(); + } + + if ($activity->getActivityType()->getUserVisible() === 2 && null === $activity->getUser()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('user')) + ->addViolation(); + } + + if ($activity->getActivityType()->getDateVisible() === 2 && null === $activity->getDate()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('date')) + ->addViolation(); + } + + if ($activity->getActivityType()->getLocationVisible() === 2 && null === $activity->getLocation()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('location')) + ->addViolation(); + } + + if ($activity->getActivityType()->getDurationTimeVisible() === 2 && null === $activity->getDurationTime()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('duration time')) + ->addViolation(); + } + + if ($activity->getActivityType()->getTravelTimeVisible() === 2 && null === $activity->getTravelTime()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('travel time')) + ->addViolation(); + } + + if ($activity->getActivityType()->getAttendeeVisible() === 2 && null === $activity->getAttendee()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('attendee')) + ->addViolation(); + } + + if ($activity->getActivityType()->getReasonsVisible() === 2 && null === $activity->getReasons()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('reasons')) + ->addViolation(); + } + + if ($activity->getActivityType()->getCommentVisible() === 2 && null === $activity->getComment()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('comment')) + ->addViolation(); + } + + if ($activity->getActivityType()->getSentReceivedVisible() === 2 && null === $activity->getSentReceived()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('sent/received')) + ->addViolation(); + } + + if ($activity->getActivityType()->getDocumentsVisible() === 2 && null === $activity->getDocuments()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('document')) + ->addViolation(); + } + + if ($activity->getActivityType()->getEmergencyVisible() === 2 && null === $activity->getEmergency()) { + $this->context + ->buildViolation($constraint->makeIsRequiredMessage('emergency')) + ->addViolation(); + } + + if ($activity->getActivityType()->getSocialIssuesVisible() === 2 && $activity->getSocialIssues()->count() === 0) { + $this->context + ->buildViolation($constraint->socialIssuesMessage) + ->addViolation(); + } + + if ($activity->getActivityType()->getSocialActionsVisible() === 2 && $activity->getSocialActions()->count() === 0) { + $this->context + ->buildViolation($constraint->socialActionsMessage) + ->addViolation(); + } + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services.yaml b/src/Bundle/ChillActivityBundle/config/services.yaml index 4e93e38be..1ca413f0e 100644 --- a/src/Bundle/ChillActivityBundle/config/services.yaml +++ b/src/Bundle/ChillActivityBundle/config/services.yaml @@ -27,3 +27,8 @@ services: Chill\ActivityBundle\Repository\: resource: '../Repository/' + + Chill\ActivityBundle\Validator\Constraints\: + autowire: true + autoconfigure: true + resource: '../Validator/Constraints/' diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index d0c3ddc6d..959eee233 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -139,34 +139,40 @@ ActivityReasonCategory is inactive and won't be proposed: La catégorie est inac # activity type type admin ActivityType list: Types d'activités Create a new activity type: Créer un nouveau type d'activité -Persons visible: Visibilté du champ Personnes +Persons visible: Visibilité du champ Personnes Persons label: Libellé du champ Personnes -User visible: Visibilté du champ Utilisateur +User visible: Visibilité du champ Utilisateur User label: Libellé du champ Utilisateur -Date visible: Visibilté du champ Date +Date visible: Visibilité du champ Date Date label: Libellé du champ Date -Place visible: Visibilté du champ Lieu +Place visible: Visibilité du champ Lieu Place label: Libellé du champ Lieu -Third parties visible: Visibilté du champ Tiers +Third parties visible: Visibilité du champ Tiers Third parties label: Libellé du champ Tiers -Duration time visible: Visibilté du champ Durée +Duration time visible: Visibilité du champ Durée Duration time label: Libellé du champ Durée -Travel time visible: Visibilté du champ Durée de déplacement +Travel time visible: Visibilité du champ Durée de déplacement Travel time label: Libellé du champ Durée de déplacement -Attendee visible: Visibilté du champ Présence de l'usager +Attendee visible: Visibilité du champ Présence de l'usager Attendee label: Libellé du champ Présence de l'usager -Reasons visible: Visibilté du champ Sujet +Reasons visible: Visibilité du champ Sujet Reasons label: Libellé du champ Sujet -Comment visible: Visibilté du champ Commentaire +Comment visible: Visibilité du champ Commentaire Comment label: Libellé du champ Commentaire -Emergency visible: Visibilté du champ Urgent +Emergency visible: Visibilité du champ Urgent Emergency label: Libellé du champ Urgent -Accompanying period visible: Visibilté du champ Période d'accompagnement +Accompanying period visible: Visibilité du champ Période d'accompagnement Accompanying period label: Libellé du champ Période d'accompagnement -Social data visible: Visibilté du champ Données sociales -Social data label: Libellé du champ Données sociales -Users visible: Visibilté du champ Utilisateurs +Social issues visible: Visibilité du champ Problématiques sociales +Social issues label: Libellé du champ Problématiques sociales +Social actions visible: Visibilité du champ Action sociale +Social actions label: Libellé du champ Action sociale +Users visible: Visibilité du champ Utilisateurs Users label: Libellé du champ Utilisateurs +Sent received visible: Visibilité du champ Entrant / Sortant +Sent received label: Libellé du champ Entrant / Sortant +Documents visible: Visibilité du champ Documents +Documents label: Libellé du champ Documents # activity type category admin ActivityTypeCategory list: Liste des catégories des types d'activité diff --git a/src/Bundle/ChillActivityBundle/translations/validators.fr.yml b/src/Bundle/ChillActivityBundle/translations/validators.fr.yml index edda0b67b..072ac55d2 100644 --- a/src/Bundle/ChillActivityBundle/translations/validators.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/validators.fr.yml @@ -1,2 +1,22 @@ The reasons's level should not be empty: Le niveau du sujet ne peut pas être vide At least one reason must be choosen: Au moins un sujet doit être choisi +For this type of activity, you must add at least one person: Pour ce type d'activité, vous devez ajouter au moins un usager +For this type of activity, you must add at least one user: Pour ce type d'activité, vous devez ajouter au moins un utilisateur +For this type of activity, you must add at least one third party: Pour ce type d'activité, vous devez ajouter au moins un tiers +For this type of activity, user is required: Pour ce type d'activité, l'utilisateur est requis +For this type of activity, date is required: Pour ce type d'activité, la date est requise +For this type of activity, location is required: Pour ce type d'activité, la localisation est requise +For this type of activity, attendee is required: Pour ce type d'activité, le champ "Présence de la personne" est requis +For this type of activity, duration time is required: Pour ce type d'activité, la durée est requise +For this type of activity, travel time is required: Pour ce type d'activité, la durée du trajet est requise +For this type of activity, reasons is required: Pour ce type d'activité, le champ "sujet" est requis +For this type of activity, comment is required: Pour ce type d'activité, un commentaire est requis +For this type of activity, sent/received is required: Pour ce type d'activité, le champ Entrant/Sortant est requis +For this type of activity, document is required: Pour ce type d'activité, un document est requis +For this type of activity, emergency is required: Pour ce type d'activité, le champ "Urgent" est requis +For this type of activity, accompanying period is required: Pour ce type d'activité, le parcours d'accompagnement est requis +For this type of activity, you must add at least one social issue: Pour ce type d'activité, vous devez ajouter au moins une problématique sociale +For this type of activity, you must add at least one social action: Pour ce type d'activité, vous devez indiquez au moins une action sociale + +# admin +This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales" diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidityValidator.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidityValidator.php index 167553909..275ab281f 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidityValidator.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidityValidator.php @@ -32,7 +32,7 @@ class LocationValidityValidator extends ConstraintValidator } if (!$period instanceof AccompanyingPeriod) { - throw new UnexpectedValueException($value, AccompanyingPeriod::class); + throw new UnexpectedValueException($period, AccompanyingPeriod::class); } if ($period->getLocationStatus() === 'person') {