diff --git a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/CollectionDocGenNormalizer.php b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/CollectionDocGenNormalizer.php index 196018a03..b4e99bb98 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/CollectionDocGenNormalizer.php +++ b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/CollectionDocGenNormalizer.php @@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\Serializer\Normalizer; use ArrayObject; use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Collections\ReadableCollection; use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; @@ -51,7 +52,9 @@ class CollectionDocGenNormalizer implements ContextAwareNormalizerInterface, Nor return false; } - return $data instanceof Collection - || (null === $data && Collection::class === ($context['docgen:expects'] ?? null)); + return $data instanceof ReadableCollection + || (null === $data && Collection::class === ($context['docgen:expects'] ?? null)) + || (null === $data && ReadableCollection::class === ($context['docgen:expects'] ?? null)) + ; } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php index 3807ee9ee..bbf12b0fd 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php +++ b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php @@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\Serializer\Normalizer; use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use Doctrine\Common\Collections\ReadableCollection; use ReflectionClass; use RuntimeException; use Symfony\Component\PropertyAccess\PropertyAccess; @@ -271,6 +272,14 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte if ($isTranslatable) { $data[$key] = $this->translatableStringHelper ->localize($value); + } elseif ($value instanceof ReadableCollection) { + // when normalizing collection, we should not preserve keys (to ensure that the result is a list) + // this is why we make call to the normalizer again to use the CollectionDocGenNormalizer + $data[$key] = + $this->normalizer->normalize($value, $format, array_merge( + $objectContext, + $attribute->getNormalizationContextForGroups($expectedGroups) + )); } elseif (is_iterable($value)) { $arr = []; diff --git a/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/CollectionDocGenNormalizerTest.php b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/CollectionDocGenNormalizerTest.php new file mode 100644 index 000000000..7bfddadca --- /dev/null +++ b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/CollectionDocGenNormalizerTest.php @@ -0,0 +1,52 @@ +normalizer = self::$container->get(NormalizerInterface::class); + } + + public function testNormalizeFilteredArray(): void + { + $coll = new ArrayCollection([ + (object) ['v' => 'foo'], + (object) ['v' => 'bar'], + (object) ['v' => 'baz'], + ]); + + //filter to get non continuous indexes + $criteria = new Criteria(); + $criteria->where(Criteria::expr()->neq('v', 'bar')); + + $filtered = $coll->matching($criteria); + $normalized = $this->normalizer->normalize($filtered, 'docgen', []); + + self::assertIsArray($normalized); + self::assertArrayHasKey(0, $normalized); + self::assertArrayHasKey(1, $normalized); + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php index acd4119a1..093b882ce 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php @@ -18,6 +18,7 @@ use Chill\PersonBundle\Entity\Person; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** @@ -39,7 +40,7 @@ final class HouseholdNormalizerTest extends KernelTestCase $this->entityManager = self::$container->get(EntityManagerInterface::class); } - public function testNormalizationRecursive() + public function testNormalizationRecursive(): void { $person = new Person(); $person->setFirstName('ok')->setLastName('ok'); @@ -67,4 +68,53 @@ final class HouseholdNormalizerTest extends KernelTestCase $this->assertArrayHasKey('type', $normalized); $this->assertEquals('household', $normalized['type']); } + + /** + * When a household have old members (members which are not "current"), + * the indexes of the household must be reset to numerical and contiguous + * indexes. This ensure that it will be mapped as a list, not as an associative + * array. + */ + public function testHouseholdDocGenNormalizationWithOldMembers(): void + { + $previousPerson = new Person(); + $previousPerson->setFirstName('ok')->setLastName('ok'); + $this->entityManager->persist($previousPerson); + $member = new HouseholdMember(); + $household = new Household(); + $position = (new Position()) + ->setShareHousehold(true) + ->setAllowHolder(true); + + $member->setPerson($previousPerson) + ->setStartDate(new DateTimeImmutable('1 year ago')) + ->setEndDate(new DateTimeImmutable('1 month ago')) + ->setPosition($position); + + $household->addMember($member); + + $currentPerson1 = new Person(); + $currentPerson1->setFirstName('p1')->setLastName('p1'); + $this->entityManager->persist($currentPerson1); + $member = new HouseholdMember(); + $member->setPerson($currentPerson1) + ->setStartDate(new DateTimeImmutable('1 year ago')) + ->setPosition($position); + $household->addMember($member); + + $normalized = $this->normalizer->normalize( + $household, + 'docgen', + [ + AbstractNormalizer::GROUPS => ['docgen:read'], + 'docgen:expects' => Household::class, + 'docgen:person:with-household' => false, + 'docgen:person:with-relations' => false, + 'docgen:person:with-budget' => false, + ] + ); + + self::assertIsArray($normalized); + self::assertArrayHasKey(0, $normalized['currentMembers']); + } }