diff --git a/CHANGELOG.md b/CHANGELOG.md index ed24da1c1..a9e95a0d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ and this project adheres to ## Unreleased -* [person] add maritalStatusComment to PersonDocGenNormalizer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/582s) +* [person] prevent circular references in PersonDocGenNormalizer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/527) +* [person] add maritalStatusComment to PersonDocGenNormalizer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/582) * [main] avoid address reference search on undefined post code (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/561) * [person] prevent duplicate relationship in filiation/household graph (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/560) diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php index 4fbfa8162..d1d6f0a95 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php @@ -23,6 +23,7 @@ use Chill\PersonBundle\Repository\Relationships\RelationshipRepository; use Chill\PersonBundle\Templating\Entity\PersonRenderInterface; use DateTimeInterface; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\DataFixtures\Exception\CircularReferenceException; use libphonenumber\PhoneNumber; use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; @@ -52,6 +53,8 @@ class PersonDocGenNormalizer implements private TranslatorInterface $translator; + private const CIRCULAR_KEY = 'person:circular'; + public function __construct( PersonRenderInterface $personRender, RelationshipRepository $relationshipRepository, @@ -68,6 +71,17 @@ class PersonDocGenNormalizer implements public function normalize($person, $format = null, array $context = []) { + + try { + $context = $this->addCircularToContext($person, $context); + } catch (CircularReferenceException $circularReferenceException) { + return [ + 'isNull' => true, + 'isCircular' => true, + 'text' => '' + ]; + } + /** @var Person $person */ $dateContext = $context; $dateContext['docgen:expects'] = DateTimeInterface::class; @@ -178,6 +192,36 @@ class PersonDocGenNormalizer implements ); } + private function addCircularToContext($person, $context) { + if (null === $person) { + $key = 'n'; + } else { + $key = spl_object_hash($person); + } + + if (!\array_key_exists(self::CIRCULAR_KEY, $context)) { + $context[self::CIRCULAR_KEY] = [$key]; + + return $context; + } + + $occurences = array_reduce($context[self::CIRCULAR_KEY], function ($carry, $item) use ($key) { + if ($key === $item) { + $carry++; + } + return $carry; + }, 0); + + if (2 <= $occurences) { + throw new CircularReferenceException(); + } + + $context[self::CIRCULAR_KEY][] = $key; + + return $context; + } + + private function hasGroup($context, string $group): bool { $groups = $context[AbstractNormalizer::GROUPS] ?? [];