From 40fcb090822c53be0fde41c9e4a516daf5cdff65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 21 Jun 2021 13:38:43 +0200 Subject: [PATCH] layout for form --- .../CRUD/Controller/ApiController.php | 14 +- .../Resources/public/js/date.js | 11 +- .../AccompanyingCourseApiController.php | 15 ++ .../ChillPersonExtension.php | 13 ++ .../Entity/AccompanyingPeriod.php | 36 +++++ .../AccompanyingPeriodWork.php | 108 ++++++++++--- .../Entity/SocialWork/SocialAction.php | 6 + .../AccompanyingCourseWorkCreate/App.vue | 152 +++++++++++++----- .../AccompanyingCourseWorkCreate/store.js | 93 +++++++++-- .../vuejs/_api/AccompanyingCourseWork.js | 30 ++++ .../vuejs/_api/SocialWorkSocialAction.js | 2 +- .../AccompanyingCourseWork/create.html.twig | 7 +- .../Normalizer/SocialActionNormalizer.php | 2 + .../ChillPersonBundle/chill.api.specs.yaml | 49 ++++++ .../migrations/Version20210620143757.php | 51 ++++++ .../translations/messages.fr.yml | 5 + 16 files changed, 516 insertions(+), 78 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/AccompanyingCourseWork.js create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20210620143757.php diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php index 9686a7b98..cab0bcdcb 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php @@ -359,9 +359,10 @@ class ApiController extends AbstractCRUDController * 6. validate the base entity (not the deserialized one). Groups are fetched from getValidationGroups, validation is perform by `validate` * 7. run onAfterValidation * 8. if errors, return a 422 response with errors - * 9. flush the data - * 10. run onAfterFlush - * 11. return a 202 response for DELETE with empty body, or HTTP 200 for post with serialized posted entity + * 9. if $forcePersist === true, persist the entity + * 10. flush the data + * 11. run onAfterFlush + * 12. return a 202 response for DELETE with empty body, or HTTP 200 for post with serialized posted entity * * @param string action * @param mixed id @@ -370,11 +371,12 @@ class ApiController extends AbstractCRUDController * @param string $property the name of the property. This will be used to make a `add+$property` and `remove+$property` method * @param string $postedDataType the type of the posted data (the content) * @param string $postedDataContext a context to deserialize posted data (the content) + * @param bool $forcePersist force to persist the created element (only for POST request) * @throw BadRequestException if unable to deserialize the posted data * @throw BadRequestException if the method is not POST or DELETE * */ - protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, $postedDataContext = []): Response + protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, array $postedDataContext = [], bool $forcePersist = false): Response { $entity = $this->getEntity($action, $id, $request); @@ -429,6 +431,10 @@ class ApiController extends AbstractCRUDController return $this->json($errors, 422); } + if ($forcePersist && $request->getMethod() === Request::METHOD_POST) { + $this->getDoctrine()->getManager()->persist($postedData); + } + $this->getDoctrine()->getManager()->flush(); diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/date.js b/src/Bundle/ChillMainBundle/Resources/public/js/date.js index a11bc15bf..e49a05972 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/js/date.js +++ b/src/Bundle/ChillMainBundle/Resources/public/js/date.js @@ -11,9 +11,12 @@ * * Do not take time into account * - * **Experimental** */ const dateToISO = (date) => { + if (null === date) { + return null; + } + return [ date.getFullYear(), (date.getMonth() + 1).toString().padStart(2, '0'), @@ -36,10 +39,12 @@ const ISOToDate = (str) => { /** * Return a date object from iso string formatted as YYYY-mm-dd:HH:MM:ss+01:00 * - * **Experimental** */ const ISOToDatetime = (str) => { - console.log(str); + if (null === str) { + return null; + } + let [cal, times] = str.split('T'), [year, month, date] = cal.split('-'), diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index 860cdfad7..8201752af 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -6,6 +6,7 @@ use Chill\MainBundle\CRUD\Controller\ApiController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -116,6 +117,20 @@ $workflow = $this->registry->get($accompanyingPeriod); return $this->addRemoveSomething('socialissue', $id, $request, $_format, 'socialIssue', SocialIssue::class, [ 'groups' => [ 'read' ] ]); } + public function workApi($id, Request $request, string $_format): Response + { + return $this->addRemoveSomething( + 'work', + $id, + $request, + $_format, + 'work', + AccompanyingPeriodWork::class, + [ 'groups' => [ 'accompanying_period_work:create' ] ], + true // force persist + ); + } + public function requestorApi($id, Request $request, string $_format): Response { /** @var AccompanyingPeriod $accompanyingPeriod */ diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index d810530ad..79dae3255 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -438,6 +438,19 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_DELETE=> \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE ] ], + 'work' => [ + 'methods' => [ + Request::METHOD_POST => true, + Request::METHOD_DELETE => false, + Request::METHOD_GET => false, + Request::METHOD_HEAD => false, + ], + 'controller_action' => 'workApi', + 'roles' => [ + Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, + Request::METHOD_DELETE => 'ALWAYS_FAILS', + ] + ], 'confirm' => [ 'methods' => [ diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 84f0c264b..47bb3c953 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -25,6 +25,7 @@ namespace Chill\PersonBundle\Entity; use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; use Chill\MainBundle\Entity\Scope; +use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin; @@ -39,6 +40,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; use Chill\MainBundle\Entity\User; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Symfony\Component\Validator\Constraints as Assert; /** * AccompanyingPeriod Class @@ -280,6 +282,15 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface */ private \DateTimeInterface $updatedAt; + /** + * @ORM\OneToMany( + * targetEntity=AccompanyingPeriodWork::class, + * mappedBy="accompanyingPeriod" + * ) + * @Assert\Valid(traverse=true) + */ + private Collection $works; + /** * AccompanyingPeriod constructor. * @@ -292,6 +303,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface $this->scopes = new ArrayCollection(); $this->socialIssues = new ArrayCollection(); $this->comments = new ArrayCollection(); + $this->works = new ArrayCollection(); } /** @@ -896,4 +908,28 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this; } + + /** + * @return AccompanyingPeriodWork[] + */ + public function getWorks(): Collection + { + return $this->works; + } + + public function addWork(AccompanyingPeriodWork $work): self + { + $this->works[] = $work; + $work->setAccompanyingPeriod($this); + + return $this; + } + + public function removeWork(AccompanyingPeriodWork $work): self + { + $this->work->removeElement($work); + $work->setAccompanyingPeriod(null); + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php index 25fbcc342..11570945e 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php @@ -7,86 +7,123 @@ use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\ThirdPartyBundle\Entity\ThirdParty; +use DateTimeInterface; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation as Serializer; +use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; +use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; +use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity * @ORM\Table(name="chill_person_accompanying_period_work") + * @Serializer\DiscriminatorMap( + * typeProperty="type", + * mapping={ + * "accompanying_period_work":AccompanyingPeriodWork::class + * } + * ) */ - class AccompanyingPeriodWork + class AccompanyingPeriodWork implements TrackCreationInterface, TrackUpdateInterface { /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") + * @Serializer\Groups({"read"}) */ - private $id; + private ?int $id; /** * @ORM\Column(type="text") + * @Serializer\Groups({"read"}) */ - private $note; + private string $note = ""; /** * @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class) + * @Serializer\Groups({"read"}) */ - private $accompanyingPeriod; + private ?AccompanyingPeriod $accompanyingPeriod = null; /** * @ORM\ManyToOne(targetEntity=SocialAction::class) + * @Serializer\Groups({"accompanying_period_work:create", "read"}) */ - private $socialAction; + private ?SocialAction $socialAction = null; /** - * @ORM\Column(type="datetime") + * @ORM\Column(type="datetime_immutable") + * @Serializer\Groups({"read"}) */ - private $createdAt; + private ?\DateTimeImmutable $createdAt = null; /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(nullable=false) + * @Serializer\Groups({"read"}) */ - private $createdBy; + private ?User $createdBy = null; /** - * @ORM\Column(type="datetime") + * @ORM\Column(type="datetime_immutable") + * @Serializer\Groups({"read"}) */ - private $startDate; + private ?\DateTimeImmutable $updatedAt = null; /** - * @ORM\Column(type="datetime") + * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\JoinColumn(nullable=false) + * @Serializer\Groups({"read"}) */ - private $endDate; + private ?User $updatedBy = null; + + /** + * @ORM\Column(type="date_immutable") + * @Serializer\Groups({"accompanying_period_work:create"}) + * @Serializer\Groups({"read"}) + */ + private \DateTimeImmutable $startDate; + + /** + * @ORM\Column(type="date_immutable", nullable=true, options={"default":null}) + * @Serializer\Groups({"accompanying_period_work:create", "read"}) + * @Assert\GreaterThan(propertyPath="startDate", + * message="accompanying_course_work.The endDate should be greater than the start date" + * ) + */ + private ?\DateTimeImmutable $endDate = null; /** * @ORM\ManyToOne(targetEntity=ThirdParty::class) + * @Serializer\Groups({"read"}) * * In schema : traitant */ - private $handlingThierParty; + private ?ThirdParty $handlingThierParty = null; /** * @ORM\Column(type="boolean") */ - private $createdAutomatically; + private bool $createdAutomatically = false; /** * @ORM\Column(type="text") */ - private $createdAutomaticallyReason; + private string $createdAutomaticallyReason = ""; /** * @ORM\OneToMany(targetEntity=AccompanyingPeriodWorkGoal::class, mappedBy="accompanyingPeriodWork") */ - private $goals; + private Collection $goals; /** * @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorks") * @ORM\JoinTable(name="chill_person_accompanying_period_work_result") */ - private $results; + private Collection $results; /** * @ORM\ManyToMany(targetEntity=ThirdParty::class) @@ -94,7 +131,7 @@ use Doctrine\ORM\Mapping as ORM; * * In schema : intervenants */ - private $thirdParties; + private Collection $thirdParties; public function __construct() { @@ -125,8 +162,17 @@ use Doctrine\ORM\Mapping as ORM; return $this->accompanyingPeriod; } + /** + * Internal: you should use `$accompanyingPeriod->removeWork($work);` or + * `$accompanyingPeriod->addWork($work);` + */ public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self { + if ($this->accompanyingPeriod instanceof AccompanyingPeriod && + $accompanyingPeriod !== $this->accompanyingPeriod) { + throw new \LogicException("A work cannot change accompanyingPeriod"); + } + $this->accompanyingPeriod = $accompanyingPeriod; return $this; @@ -144,7 +190,7 @@ use Doctrine\ORM\Mapping as ORM; return $this; } - public function getCreatedAt(): ?\DateTimeInterface + public function getCreatedAt(): ?\DateTimeImmutable { return $this->createdAt; } @@ -168,6 +214,30 @@ use Doctrine\ORM\Mapping as ORM; return $this; } + public function setUpdatedBy(User $user): TrackUpdateInterface + { + $this->updatedBy = $user; + + return $this; + } + + public function setUpdatedAt(DateTimeInterface $datetime): TrackUpdateInterface + { + $this->updatedAt = $datetime; + + return $this; + } + + public function getUpdatedAt(): ?\DateTimeImmutable + { + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + public function getStartDate(): ?\DateTimeInterface { return $this->startDate; diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php index 6e104abcb..35abe392f 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php @@ -10,6 +10,12 @@ use Symfony\Component\Serializer\Annotation as Serializer; /** * @ORM\Entity * @ORM\Table(name="chill_person_social_action") + * @Serializer\DiscriminatorMap( + * typeProperty="type", + * mapping={ + * "social_work_social_action":SocialAction::class + * } + * ) */ class SocialAction { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue index 3a3971d73..3c1f4b07a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue @@ -1,55 +1,125 @@ +