From 509b2c259012474226e1a5351cb25c8943cf7fa2 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 10 Sep 2025 15:06:13 +0200 Subject: [PATCH] fix: circular reference problems during fetches - Add code snippet to avoid circular reference in SocialActionNormalizer.php, AccompanyingPeriodWorkEvaluationDocumentNormalizer.php, AccompanyingPeriodWorkEvaluationNormalizer.php, and AccompanyingPeriodWorkNormalizer.php --- ...PeriodWorkEvaluationDocumentNormalizer.php | 17 ++++++++++++-- ...mpanyingPeriodWorkEvaluationNormalizer.php | 20 +++++++++++++---- .../AccompanyingPeriodWorkNormalizer.php | 22 +++++++++++++++++-- .../Normalizer/SocialActionNormalizer.php | 16 ++++++++++++++ 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationDocumentNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationDocumentNormalizer.php index 6c27635a4..a201e203f 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationDocumentNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationDocumentNormalizer.php @@ -29,18 +29,31 @@ class AccompanyingPeriodWorkEvaluationDocumentNormalizer implements \Symfony\Com public function normalize($object, ?string $format = null, array $context = []): array { + // Prevent circular references + $objectHash = spl_object_hash($object); + $visitedKey = 'evaluation_document_visited'; + + if (isset($context[$visitedKey][$objectHash])) { + return [ + 'id' => $object->getId(), + 'type' => 'accompanying_period_work_evaluation_document', + ]; + } + + $context[$visitedKey][$objectHash] = true; + $initial = $this->normalizer->normalize($object, $format, array_merge($context, [ self::SKIP => spl_object_hash($object), ])); $initial['workflows_availables'] = $this->metadataExtractor->availableWorkflowFor( AccompanyingPeriodWorkEvaluationDocument::class, - $object->getId() + $object->getId() ?? 0 ); $workflows = $this->entityWorkflowRepository->findBy([ 'relatedEntityClass' => AccompanyingPeriodWorkEvaluationDocument::class, - 'relatedEntityId' => $object->getId(), + 'relatedEntityId' => $object->getId() ?? 0, ]); $initial['workflows'] = $this->normalizer->normalize($workflows, 'json', $context); diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationNormalizer.php index add0ed656..a8c22d9e0 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkEvaluationNormalizer.php @@ -33,10 +33,22 @@ class AccompanyingPeriodWorkEvaluationNormalizer implements \Symfony\Component\S */ public function normalize($object, ?string $format = null, array $context = []): array { + // Prevent circular references + $objectHash = spl_object_hash($object); + $visitedKey = 'evaluation_visited'; + + if (isset($context[$visitedKey][$objectHash])) { + return [ + 'id' => $object->getId(), + 'type' => 'accompanying_period_work_evaluation', + ]; + } + + $context[$visitedKey][$objectHash] = true; + $initial = $this->normalizer->normalize($object, $format, array_merge( $context, - [self::IGNORE_EVALUATION => spl_object_hash($object)], - [AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => static fn ($object, $format, $context) => $object->getId()] + [self::IGNORE_EVALUATION => spl_object_hash($object)] )); // due to bug: https://api-platform.com/docs/core/serialization/#collection-relation @@ -52,12 +64,12 @@ class AccompanyingPeriodWorkEvaluationNormalizer implements \Symfony\Component\S $initial['workflows_availables'] = $this->metadataExtractor->availableWorkflowFor( AccompanyingPeriodWorkEvaluation::class, - $object->getId() + $object->getId() ?? 0 ); $workflows = $this->entityWorkflowRepository->findBy([ 'relatedEntityClass' => AccompanyingPeriodWorkEvaluation::class, - 'relatedEntityId' => $object->getId(), + 'relatedEntityId' => $object->getId() ?? 0, ]); $initial['workflows'] = $this->normalizer->normalize($workflows, 'json', $context); diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkNormalizer.php index 1a594aaae..cd3caa4af 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkNormalizer.php @@ -43,6 +43,24 @@ class AccompanyingPeriodWorkNormalizer implements \Symfony\Component\Serializer\ throw new UnexpectedValueException(sprintf('Object must be an instanceof AccompanyingPeriodWork or null when format is docgen, %s given', get_debug_type($object))); } + // Prevent circular references + if ($object instanceof AccompanyingPeriodWork && 'json' === $format) { + $objectHash = spl_object_hash($object); + $visitedKey = 'accompanying_period_work_visited'; + + if (isset($context[$visitedKey][$objectHash])) { + return [ + 'id' => $object->getId(), + 'type' => 'accompanying_period_work', + 'startDate' => $object->getStartDate()?->format('c'), + 'endDate' => $object->getEndDate()?->format('c'), + 'note' => $object->getNote(), + ]; + } + + $context[$visitedKey][$objectHash] = true; + } + $cleanContext = array_filter($context, fn (string|int $key) => !in_array($key, ['docgen:expects', self::IGNORE_WORK], true), ARRAY_FILTER_USE_KEY); if (null === $object && 'docgen' === $format) { @@ -106,7 +124,7 @@ class AccompanyingPeriodWorkNormalizer implements \Symfony\Component\Serializer\ // then, we add normalization for things which are not into the entity $initial['workflows_availables'] = $this->metadataExtractor->availableWorkflowFor( AccompanyingPeriodWork::class, - $object->getId() + $object->getId() ?? 0 ); $initial['workflows_availables_evaluation'] = $this->metadataExtractor->availableWorkflowFor( @@ -119,7 +137,7 @@ class AccompanyingPeriodWorkNormalizer implements \Symfony\Component\Serializer\ $workflows = $this->entityWorkflowRepository->findBy([ 'relatedEntityClass' => AccompanyingPeriodWork::class, - 'relatedEntityId' => $object->getId(), + 'relatedEntityId' => $object->getId() ?? 0, ]); $initial['workflows'] = $this->normalizer->normalize($workflows, 'json', $context); diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php index afe0c01fa..4902756fb 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php @@ -27,6 +27,22 @@ class SocialActionNormalizer implements NormalizerAwareInterface, NormalizerInte { switch ($format) { case 'json': + // Prevent circular references + $objectHash = spl_object_hash($socialAction); + $visitedKey = 'social_action_visited'; + + if (isset($context[$visitedKey][$objectHash])) { + return [ + 'id' => $socialAction->getId(), + 'type' => 'social_work_social_action', + 'text' => $this->render->renderString($socialAction, []), + 'title' => $socialAction->getTitle(), + 'ordering' => $socialAction->getOrdering(), + ]; + } + + $context[$visitedKey][$objectHash] = true; + return [ 'id' => $socialAction->getId(), 'type' => 'social_work_social_action',