[accompanyingPeriodWork] add evaluation to normalizer

This commit is contained in:
Julien Fastré 2021-08-02 00:13:08 +02:00
parent 736b2255ab
commit 3f005aaf8f
5 changed files with 297 additions and 13 deletions

View File

@ -164,8 +164,12 @@ use Symfony\Component\Validator\Constraints as Assert;
* @var Collection * @var Collection
* @ORM\OneToMany( * @ORM\OneToMany(
* targetEntity=AccompanyingPeriodWorkEvaluation::class, * targetEntity=AccompanyingPeriodWorkEvaluation::class,
* mappedBy="accompanyingPeriodWork" * mappedBy="accompanyingPeriodWork",
* cascade={"persist"},
* orphanRemoval=true
* ) * )
* @Serializer\Groups({"read"})
* @internal /!\ the serialization for read / write evaluations is handled in `AccompanyingPeriodWorkDenormalizer`
*/ */
private Collection $accompanyingPeriodWorkEvaluations; private Collection $accompanyingPeriodWorkEvaluations;
@ -398,6 +402,11 @@ use Symfony\Component\Validator\Constraints as Assert;
return $this->thirdParties; return $this->thirdParties;
} }
public function getThirdPartys(): Collection
{
return $this->getThirdParties();
}
public function addThirdParty(ThirdParty $thirdParty): self public function addThirdParty(ThirdParty $thirdParty): self
{ {
if (!$this->thirdParties->contains($thirdParty)) { if (!$this->thirdParties->contains($thirdParty)) {
@ -432,6 +441,33 @@ use Symfony\Component\Validator\Constraints as Assert;
{ {
$this->persons->removeElement($person); $this->persons->removeElement($person);
return $this;
}
/**
* @return Collection
*/
public function getAccompanyingPeriodWorkEvaluations()
{
return $this->accompanyingPeriodWorkEvaluations;
}
public function addAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self
{
if (!$this->accompanyingPeriodWorkEvaluations->contains($evaluation)) {
$this->accompanyingPeriodWorkEvaluations[] = $evaluation;
$evaluation->setAccompanyingPeriodWork($this);
}
return $this;
}
public function removeAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self
{
$this->accompanyingPeriodWorkEvaluations
->removeElement($evaluation);
$evaluation->setAccompanyingPeriodWork(null);
return $this; return $this;
} }
} }

View File

@ -12,10 +12,14 @@ use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
/** /**
* @ORM\Entity * @ORM\Entity
* @ORM\Table("chill_person_accompanying_period_work_evaluation") * @ORM\Table("chill_person_accompanying_period_work_evaluation")
* @Serializer\DiscriminatorMap(typeProperty="type", mapping={
* "accompanying_period_work_evaluation"=AccompanyingPeriodWorkEvaluation::class,
* })
*/ */
class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCreationInterface class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCreationInterface
{ {
@ -23,8 +27,9 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre
* @ORM\Id * @ORM\Id
* @ORM\GeneratedValue * @ORM\GeneratedValue
* @ORM\Column(type="integer") * @ORM\Column(type="integer")
* @Serializer\Groups({"read"})
*/ */
private ?int $id; private ?int $id = null;
/** /**
* @ORM\ManyToOne( * @ORM\ManyToOne(
@ -32,60 +37,82 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre
* inversedBy="accompanyingPeriodWorkEvaluations" * inversedBy="accompanyingPeriodWorkEvaluations"
* ) * )
*/ */
private ?AccompanyingPeriodWork $accompanyingPeriodWork; private ?AccompanyingPeriodWork $accompanyingPeriodWork = null;
/** /**
* @ORM\ManyToOne( * @ORM\ManyToOne(
* targetEntity=Evaluation::class * targetEntity=Evaluation::class
* ) * )
* @Serializer\Groups({"read"})
* @Serializer\Groups({"accompanying_period_work_evaluation:create"})
*/ */
private ?Evaluation $evaluation; private ?Evaluation $evaluation = null;
/** /**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
* @Serializer\Groups({"write"})
* @Serializer\Groups({"accompanying_period_work_evaluation:create"})
*/ */
private ?DateTimeImmutable $startDate; private ?DateTimeImmutable $startDate = null;
/** /**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
* @Serializer\Groups({"write"})
* @Serializer\Groups({"accompanying_period_work_evaluation:create"})
*/ */
private ?DateTimeImmutable $endDate; private ?DateTimeImmutable $endDate = null;
/** /**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
* @Serializer\Groups({"accompanying_period_work_evaluation:create"})
*/ */
private ?DateTimeImmutable $maxDate; private ?DateTimeImmutable $maxDate = null;
/** /**
* @ORM\Column(type="dateinterval", nullable=true, options={"default": null}) * @ORM\Column(type="dateinterval", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
* @Serializer\Groups({"accompanying_period_work_evaluation:create"})
*/ */
private ?DateInterval $warningInterval; private ?DateInterval $warningInterval = null;
/**
* @var string
* @Serializer\Groups({"read"})
* @Serializer\Groups({"write"})
* @Serializer\Groups({"accompanying_period_work_evaluation:create"})
*/
private string $comment = ''; private string $comment = '';
/** /**
* @ORM\ManyToOne( * @ORM\ManyToOne(
* targetEntity=User::class * targetEntity=User::class
* ) * )
* @Serializer\Groups({"read"})
*/ */
private ?User $createdBy; private ?User $createdBy = null;
/** /**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
*/ */
private ?DateTimeImmutable $createdAt; private ?DateTimeImmutable $createdAt = null;
/** /**
* @ORM\ManyToOne( * @ORM\ManyToOne(
* targetEntity=User::class * targetEntity=User::class
* ) * )
* @Serializer\Groups({"read"})
*/ */
private ?User $updatedBy; private ?User $updatedBy = null;
/** /**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
*/ */
private ?DateTimeImmutable $updatedAt; private ?DateTimeImmutable $updatedAt = null;
/** /**
* @var Collection * @var Collection
@ -93,6 +120,7 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre
* targetEntity=AccompanyingPeriodWorkEvaluationDocument::class, * targetEntity=AccompanyingPeriodWorkEvaluationDocument::class,
* mappedBy="accompanyingPeriodWorkEvaluation" * mappedBy="accompanyingPeriodWorkEvaluation"
* ) * )
* @Serializer\Groups({"read"})
*/ */
private Collection $documents; private Collection $documents;
@ -123,6 +151,14 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre
*/ */
public function setAccompanyingPeriodWork(?AccompanyingPeriodWork $accompanyingPeriodWork): AccompanyingPeriodWorkEvaluation public function setAccompanyingPeriodWork(?AccompanyingPeriodWork $accompanyingPeriodWork): AccompanyingPeriodWorkEvaluation
{ {
if (
$accompanyingPeriodWork instanceof AccompanyingPeriodWork
&& $this->accompanyingPeriodWork instanceof AccompanyingPeriodWork
&& $this->accompanyingPeriodWork->getId() !== $accompanyingPeriodWork->getId()) {
throw new \RuntimeException("Changing the ".
"accompanyingPeriodWork is not allowed");
}
$this->accompanyingPeriodWork = $accompanyingPeriodWork; $this->accompanyingPeriodWork = $accompanyingPeriodWork;
return $this; return $this;
} }
@ -141,7 +177,20 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre
*/ */
public function setEvaluation(?Evaluation $evaluation): AccompanyingPeriodWorkEvaluation public function setEvaluation(?Evaluation $evaluation): AccompanyingPeriodWorkEvaluation
{ {
if (
($evaluation instanceof Evaluation
&& $this->evaluation instanceof Evaluation
&& $evaluation->getId() !== $this->evaluation->getId())
||
($this->evaluation instanceof Evaluation
&& null === $evaluation)
) {
throw new \LogicException("once set, an ${self::class} cannot
change or remove the linked Evaluation::class");
}
$this->evaluation = $evaluation; $this->evaluation = $evaluation;
return $this; return $this;
} }
@ -306,4 +355,14 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre
$this->updatedAt = $updatedAt; $this->updatedAt = $updatedAt;
return $this; return $this;
} }
/**
* @return Collection
*/
public function getDocuments()
{
return $this->documents;
}
} }

View File

@ -7,10 +7,14 @@ use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
/** /**
* @ORM\Entity * @ORM\Entity
* @ORM\Table("chill_person_accompanying_period_work_evaluation_document") * @ORM\Table("chill_person_accompanying_period_work_evaluation_document")
* @Serializer\DiscriminatorMap(typeProperty="type", mapping={
* "accompanying_period_work_evaluation_document"=AccompanyingPeriodWorkEvaluationDocument::class
* })
*/ */
class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doctrine\Model\TrackCreationInterface, \Chill\MainBundle\Doctrine\Model\TrackUpdateInterface class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doctrine\Model\TrackCreationInterface, \Chill\MainBundle\Doctrine\Model\TrackUpdateInterface
{ {
@ -22,8 +26,10 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
* *
* @internal the default name exceeds 64 characters, we must set manually: * @internal the default name exceeds 64 characters, we must set manually:
* @ORM\SequenceGenerator(sequenceName="chill_person_social_work_eval_doc_id_seq", allocationSize=1, initialValue=1000) * @ORM\SequenceGenerator(sequenceName="chill_person_social_work_eval_doc_id_seq", allocationSize=1, initialValue=1000)
* @Serializer\Groups({"read"})
*/ */
private ?int $id; private ?int $id;
/** /**
* @var AccompanyingPeriodWorkEvaluation|null * @var AccompanyingPeriodWorkEvaluation|null
* @ORM\ManyToOne( * @ORM\ManyToOne(
@ -37,11 +43,13 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
* @ORM\ManyToOne( * @ORM\ManyToOne(
* targetEntity=User::class * targetEntity=User::class
* ) * )
* @Serializer\Groups({"read"})
*/ */
private ?User $createdBy; private ?User $createdBy;
/** /**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
*/ */
private ?\DateTimeImmutable $createdAt; private ?\DateTimeImmutable $createdAt;
@ -49,11 +57,13 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
* @ORM\ManyToOne( * @ORM\ManyToOne(
* targetEntity=User::class * targetEntity=User::class
* ) * )
* @Serializer\Groups({"read"})
*/ */
private ?User $updatedBy; private ?User $updatedBy;
/** /**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
*/ */
private ?DateTimeImmutable $updatedAt; private ?DateTimeImmutable $updatedAt;
@ -121,5 +131,44 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
return $this; return $this;
} }
/**
* @return int|null
*/
public function getId(): ?int
{
return $this->id;
}
/**
* @return User|null
*/
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
/**
* @return \DateTimeImmutable|null
*/
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
/**
* @return User|null
*/
public function getUpdatedBy(): ?User
{
return $this->updatedBy;
}
/**
* @return DateTimeImmutable|null
*/
public function getUpdatedAt(): ?DateTimeInterface
{
return $this->updatedAt;
}
} }

View File

@ -3,10 +3,14 @@
namespace Chill\PersonBundle\Entity\SocialWork; namespace Chill\PersonBundle\Entity\SocialWork;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
/** /**
* @ORM\Entity * @ORM\Entity
* @ORM\Table(name="chill_person_social_work_evaluation") * @ORM\Table(name="chill_person_social_work_evaluation")
* @Serializer\DiscriminatorMap(typeProperty="type", mapping={
* "social_work_evaluation"=Evaluation::class
* })
*/ */
class Evaluation class Evaluation
{ {
@ -14,21 +18,25 @@ class Evaluation
* @ORM\Id * @ORM\Id
* @ORM\GeneratedValue * @ORM\GeneratedValue
* @ORM\Column(type="integer") * @ORM\Column(type="integer")
* @Serializer\Groups({"read"})
*/ */
private $id; private $id;
/** /**
* @ORM\Column(type="json") * @ORM\Column(type="json")
* @Serializer\Groups({"read"})
*/ */
private $title = []; private $title = [];
/** /**
* @ORM\Column(type="dateinterval", nullable=true, options={"default": null}) * @ORM\Column(type="dateinterval", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
*/ */
private $delay; private $delay;
/** /**
* @ORM\Column(type="dateinterval", nullable=true, options={"default": null}) * @ORM\Column(type="dateinterval", nullable=true, options={"default": null})
* @Serializer\Groups({"read"})
*/ */
private $notificationDelay; private $notificationDelay;

View File

@ -0,0 +1,132 @@
<?php
namespace Chill\PersonBundle\Serializer\Normalizer;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\SocialWork\Goal;
use Chill\PersonBundle\Entity\SocialWork\Result;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\Exception\BadMethodCallException;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
/**
* This denormalizer rely on AbstractNormalizer for most of the job, and
* add some logic for synchronizing collection.
*/
class AccompanyingPeriodWorkDenormalizer implements DenormalizerAwareInterface, ContextAwareDenormalizerInterface
{
use DenormalizerAwareTrait;
use ObjectToPopulateTrait;
private AccompanyingPeriodWorkRepository $workRepository;
private EntityManagerInterface $em;
public const GROUP_CREATE = 'accompanying_period_work:create';
public const GROUP_EDIT = 'accompanying_period_work:edit';
/**
* @param AccompanyingPeriodWorkRepository $workRepository
*/
public function __construct(
AccompanyingPeriodWorkRepository $workRepository,
EntityManagerInterface $em
) {
$this->workRepository = $workRepository;
$this->em = $em;
}
/**
* @inheritDoc
*/
public function denormalize($data, string $type, string $format = null, array $context = [])
{
$work = $this->denormalizer->denormalize($data, $type, $format, \array_merge($context,
['skip' => self::class]));
if (\in_array('accompanying_period_work:edit', $context['groups'] ?? [])) {
$this->handleEvaluationCollection($data, $work, $format, $context);
}
return $work;
}
private function handleEvaluationCollection(array $data, AccompanyingPeriodWork $work, string $format, array $context)
{
$dataById = [];
$dataWithoutId = [];
foreach ($data['accompanyingPeriodWorkEvaluations'] as $e) {
if (\array_key_exists('id', $e)) {
$dataById[$e['id']] = $e;
} else {
$dataWithoutId[] = $e;
}
}
// partition the separate kept evaluations and removed one
list($kept, $removed) = $work->getAccompanyingPeriodWorkEvaluations()
->partition(
fn(int $key, AccompanyingPeriodWorkEvaluation $a) => \array_key_exists($a->getId(), $dataById)
);
// remove the evaluations from work
foreach ($removed as $r) {
$work->removeAccompanyingPeriodWorkEvaluation($r);
}
// handle the evaluation kept
foreach ($kept as $k) {
$this->denormalizer->denormalize(
$dataById[$k->getId()],
AccompanyingPeriodWorkEvaluation::class,
$format,
\array_merge(
$context,
[
'groups' => [ 'write' ],
AbstractNormalizer::OBJECT_TO_POPULATE => $k
]
)
);
}
// create new evaluation
foreach ($dataWithoutId as $newData) {
$evaluation = $this->denormalizer->denormalize(
$newData,
AccompanyingPeriodWorkEvaluation::class,
$format,
\array_merge($context, ['groups' => [ 'accompanying_period_work_evaluation:create']]
)
);
$work->addAccompanyingPeriodWorkEvaluation($evaluation);
}
}
/**
* @inheritDoc
*/
public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool
{
return $type === AccompanyingPeriodWork::class
&& ($context['skip'] ?? null) !== self::class
&& \is_array($data)
&& \array_key_exists("type", $data)
&& $data["type"] === 'accompanying_period_work';
}
}