From 9778fb2e19dc57783bd89f7add778b4d1bee95e7 Mon Sep 17 00:00:00 2001 From: Adrien Brault Date: Tue, 29 Mar 2016 20:02:18 +0200 Subject: [PATCH] Avoid serializing the same object twice --- .../EventSubscriber/JsonEventSubscriber.php | 4 ++ .../EventSubscriber/XmlEventSubscriber.php | 12 ++++-- .../Tests/Fixtures/CircularReference1.php | 31 +++++++++++++ .../Tests/Fixtures/CircularReference2.php | 31 +++++++++++++ tests/Hateoas/Tests/HateoasBuilderTest.php | 43 +++++++++++++++++++ 5 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 tests/Hateoas/Tests/Fixtures/CircularReference1.php create mode 100644 tests/Hateoas/Tests/Fixtures/CircularReference2.php diff --git a/src/Hateoas/Serializer/EventSubscriber/JsonEventSubscriber.php b/src/Hateoas/Serializer/EventSubscriber/JsonEventSubscriber.php index fb9a3d0f..b4fee474 100644 --- a/src/Hateoas/Serializer/EventSubscriber/JsonEventSubscriber.php +++ b/src/Hateoas/Serializer/EventSubscriber/JsonEventSubscriber.php @@ -80,6 +80,8 @@ public function onPostSerialize(ObjectEvent $event) $object = $event->getObject(); $context = $event->getContext(); + $context->startVisiting($object); + $embeddeds = $this->embeddedsFactory->create($object, $context); $links = $this->linksFactory->create($object, $context); @@ -93,5 +95,7 @@ public function onPostSerialize(ObjectEvent $event) if (count($embeddeds) > 0) { $this->jsonSerializer->serializeEmbeddeds($embeddeds, $event->getVisitor(), $context); } + + $context->stopVisiting($object); } } diff --git a/src/Hateoas/Serializer/EventSubscriber/XmlEventSubscriber.php b/src/Hateoas/Serializer/EventSubscriber/XmlEventSubscriber.php index e0e6925a..cb07cff4 100644 --- a/src/Hateoas/Serializer/EventSubscriber/XmlEventSubscriber.php +++ b/src/Hateoas/Serializer/EventSubscriber/XmlEventSubscriber.php @@ -57,9 +57,13 @@ public function __construct(XmlSerializerInterface $xmlSerializer, LinksFactory public function onPostSerialize(ObjectEvent $event) { - $context = $event->getContext(); - $embeddeds = $this->embeddedsFactory->create($event->getObject(), $event->getContext()); - $links = $this->linksFactory->create($event->getObject(), $event->getContext()); + $object = $event->getObject(); + $context = $event->getContext(); + + $context->startVisiting($object); + + $embeddeds = $this->embeddedsFactory->create($object, $context); + $links = $this->linksFactory->create($object, $context); if (count($links) > 0) { $this->xmlSerializer->serializeLinks($links, $event->getVisitor(), $context); @@ -68,5 +72,7 @@ public function onPostSerialize(ObjectEvent $event) if (count($embeddeds) > 0) { $this->xmlSerializer->serializeEmbeddeds($embeddeds, $event->getVisitor(), $context); } + + $context->stopVisiting($object); } } diff --git a/tests/Hateoas/Tests/Fixtures/CircularReference1.php b/tests/Hateoas/Tests/Fixtures/CircularReference1.php new file mode 100644 index 00000000..a889385b --- /dev/null +++ b/tests/Hateoas/Tests/Fixtures/CircularReference1.php @@ -0,0 +1,31 @@ +reference2 = $reference2; + } + + public function getReference2() + { + return $this->reference2; + } +} diff --git a/tests/Hateoas/Tests/Fixtures/CircularReference2.php b/tests/Hateoas/Tests/Fixtures/CircularReference2.php new file mode 100644 index 00000000..0194b9e5 --- /dev/null +++ b/tests/Hateoas/Tests/Fixtures/CircularReference2.php @@ -0,0 +1,31 @@ +reference1 = $reference1; + } + + public function getReference1() + { + return $this->reference1; + } +} diff --git a/tests/Hateoas/Tests/HateoasBuilderTest.php b/tests/Hateoas/Tests/HateoasBuilderTest.php index f4135adf..9f440708 100644 --- a/tests/Hateoas/Tests/HateoasBuilderTest.php +++ b/tests/Hateoas/Tests/HateoasBuilderTest.php @@ -3,6 +3,8 @@ namespace Hateoas\Tests; use Hateoas\HateoasBuilder; +use Hateoas\Tests\Fixtures\CircularReference1; +use Hateoas\Tests\Fixtures\CircularReference2; use Hateoas\UrlGenerator\CallableUrlGenerator; use JMS\Serializer\SerializationContext; use Hateoas\Tests\Fixtures\AdrienBrault; @@ -85,4 +87,45 @@ public function testAlternativeUrlGenerator() $hateoas->serialize(new WithAlternativeRouter(), 'xml') ); } + + public function testCyclicalReferences() + { + $hateoas = HateoasBuilder::create()->build(); + + $reference1 = new CircularReference1(); + $reference2 = new CircularReference2(); + $reference1->setReference2($reference2); + $reference2->setReference1($reference1); + + $this->assertSame( + << + + + + + + + + +XML + , + $hateoas->serialize($reference1, 'xml') + ); + + $this->assertSame( + '{' + .'"name":"reference1",' + .'"_embedded":{' + .'"reference2":{' + .'"name":"reference2",' + .'"_embedded":{' + .'"reference1":null' + .'}' + .'}' + .'}' + .'}', + $hateoas->serialize($reference1, 'json') + ); + } }