Skip to content

Commit

Permalink
Merge pull request #246 from goetas/max-depth
Browse files Browse the repository at this point in the history
Max depth issues when used with "embedded" relations
  • Loading branch information
willdurand committed Apr 15, 2017
2 parents ada89d8 + b68216d commit 7e1a233
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 29 deletions.
6 changes: 1 addition & 5 deletions .travis.yml
Expand Up @@ -5,10 +5,10 @@ cache:
- $COMPOSER_CACHE_DIR

php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- hhvm

allow_failures:
Expand All @@ -23,10 +23,6 @@ env:
- SYMFONY_VERSION=3.0.*

matrix:
#Symfony 3.0 requires PHP 5.5
exclude:
- php: 5.4
env: SYMFONY_VERSION=3.0.*
fast_finish: true
allow_failures:
- php: hhvm
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Expand Up @@ -13,11 +13,11 @@
}
],
"require": {
"php": ">=5.4",
"php": "^5.5|^7.0",
"doctrine/common": "~2.0",
"doctrine/annotations": "~1.0",
"jms/metadata": "~1.1",
"jms/serializer": "~1.0",
"jms/serializer": "^1.6.1",
"symfony/expression-language": "~2.4 || ~3.0",
"phpoption/phpoption": ">=1.1.0,<2.0-dev"
},
Expand Down
5 changes: 4 additions & 1 deletion src/Hateoas/Factory/EmbeddedsFactory.php
Expand Up @@ -6,6 +6,7 @@
use Hateoas\Expression\ExpressionEvaluator;
use Hateoas\Model\Embedded;
use Hateoas\Serializer\ExclusionManager;
use Hateoas\Serializer\Metadata\RelationPropertyMetadata;
use JMS\Serializer\SerializationContext;

/**
Expand Down Expand Up @@ -59,7 +60,9 @@ public function create($object, SerializationContext $context)
$data = $this->expressionEvaluator->evaluate($relation->getEmbedded()->getContent(), $object);
$xmlElementName = $this->expressionEvaluator->evaluate($relation->getEmbedded()->getXmlElementName(), $object);

$embeddeds[] = new Embedded($rel, $data, $xmlElementName);
$propertyMetadata = new RelationPropertyMetadata($relation->getEmbedded()->getExclusion(), $relation);

$embeddeds[] = new Embedded($rel, $data, $propertyMetadata, $xmlElementName);
}

return $embeddeds;
Expand Down
22 changes: 19 additions & 3 deletions src/Hateoas/Model/Embedded.php
@@ -1,6 +1,7 @@
<?php

namespace Hateoas\Model;
use Hateoas\Serializer\Metadata\RelationPropertyMetadata;

/**
* @author Adrien Brault <adrien.brault@gmail.com>
Expand All @@ -23,17 +24,32 @@ class Embedded
private $xmlElementName;

/**
* @param string $rel
* @param mixed $data
* @var RelationPropertyMetadata
*/
private $metadata;

/**
* @param string $rel
* @param mixed $data
* @param string|null $xmlElementName
* @param RelationPropertyMetadata $metadata
*/
public function __construct($rel, $data, $xmlElementName = null)
public function __construct($rel, $data, RelationPropertyMetadata $metadata, $xmlElementName = null)
{
$this->rel = $rel;
$this->data = $data;
$this->metadata = $metadata;
$this->xmlElementName = $xmlElementName;
}

/**
* @return RelationPropertyMetadata
*/
public function getMetadata()
{
return $this->metadata;
}

/**
* @return mixed
*/
Expand Down
4 changes: 4 additions & 0 deletions src/Hateoas/Serializer/JsonHalSerializer.php
Expand Up @@ -44,6 +44,8 @@ public function serializeEmbeddeds(array $embeddeds, JsonSerializationVisitor $v
$serializedEmbeddeds = array();
$multiple = array();
foreach ($embeddeds as $embedded) {
$context->pushPropertyMetadata($embedded->getMetadata());

if (!isset($serializedEmbeddeds[$embedded->getRel()])) {
$serializedEmbeddeds[$embedded->getRel()] = $context->accept($embedded->getData());
} elseif (!isset($multiple[$embedded->getRel()])) {
Expand All @@ -56,6 +58,8 @@ public function serializeEmbeddeds(array $embeddeds, JsonSerializationVisitor $v
} else {
$serializedEmbeddeds[$embedded->getRel()][] = $context->accept($embedded->getData());
}

$context->popPropertyMetadata();
}

$visitor->addData('_embedded', $serializedEmbeddeds);
Expand Down
19 changes: 13 additions & 6 deletions src/Hateoas/Serializer/XmlHalSerializer.php
Expand Up @@ -2,6 +2,7 @@

namespace Hateoas\Serializer;

use Hateoas\Model\Embedded;
use Hateoas\Representation\Resource;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\XmlSerializationVisitor;
Expand Down Expand Up @@ -53,9 +54,7 @@ public function serializeEmbeddeds(array $embeddeds, XmlSerializationVisitor $vi
$visitor->setCurrentNode($entryNode);
$visitor->getCurrentNode()->setAttribute('rel', $embedded->getRel());

if (null !== $node = $context->accept($data)) {
$visitor->getCurrentNode()->appendChild($node);
}
$this->acceptDataAndAppend($embedded, $data, $visitor, $context);

$visitor->revertCurrentNode();
}
Expand All @@ -69,11 +68,19 @@ public function serializeEmbeddeds(array $embeddeds, XmlSerializationVisitor $vi
$visitor->setCurrentNode($entryNode);
$visitor->getCurrentNode()->setAttribute('rel', $embedded->getRel());

if (null !== $node = $context->accept($embedded->getData())) {
$visitor->getCurrentNode()->appendChild($node);
}
$this->acceptDataAndAppend($embedded, $embedded->getData(), $visitor, $context);

$visitor->revertCurrentNode();
}
}

private function acceptDataAndAppend(Embedded $embedded, $data, XmlSerializationVisitor $visitor, SerializationContext $context)
{
$context->pushPropertyMetadata($embedded->getMetadata());

if (null !== $node = $context->accept($data)) {
$visitor->getCurrentNode()->appendChild($node);
}
$context->popPropertyMetadata();
}
}
19 changes: 14 additions & 5 deletions src/Hateoas/Serializer/XmlSerializer.php
Expand Up @@ -63,14 +63,12 @@ public function serializeEmbeddeds(array $embeddeds, XmlSerializationVisitor $vi
$visitor->getCurrentNode()->appendChild($entryNode);
$visitor->setCurrentNode($entryNode);

if (null !== $node = $context->accept($entry)) {
$visitor->getCurrentNode()->appendChild($node);
}
$this->acceptDataAndAppend($embedded, $entry, $visitor, $context);

$visitor->revertCurrentNode();
}
} elseif (null !== $node = $context->accept($embedded->getData())) {
$visitor->getCurrentNode()->appendChild($node);
} else {
$this->acceptDataAndAppend($embedded, $embedded->getData(), $visitor, $context);
}

$visitor->revertCurrentNode();
Expand All @@ -92,4 +90,15 @@ private function getElementName($data, Embedded $embedded = null)

return $elementName ?: 'entry';
}

private function acceptDataAndAppend(Embedded $embedded, $data, XmlSerializationVisitor $visitor, SerializationContext $context)
{
$context->pushPropertyMetadata($embedded->getMetadata());

if (null !== $node = $context->accept($data)) {
$visitor->getCurrentNode()->appendChild($node);
}

$context->popPropertyMetadata();
}
}
18 changes: 18 additions & 0 deletions tests/Hateoas/Tests/Fixtures/Gh236Bar.php
@@ -0,0 +1,18 @@
<?php

namespace Hateoas\Tests\Fixtures;

use JMS\Serializer\Annotation as Serializer;

class Gh236Bar
{
/**
* @Serializer\Expose()
*/
public $xxx = 'yyy';

/**
* @Serializer\Expose()
*/
public $inner;
}
40 changes: 40 additions & 0 deletions tests/Hateoas/Tests/Fixtures/Gh236Foo.php
@@ -0,0 +1,40 @@
<?php

namespace Hateoas\Tests\Fixtures;

use Hateoas\Configuration\Annotation as Hateoas;
use JMS\Serializer\Annotation as Serializer;


/**
* @Hateoas\Relation(
* name = "b_embed",
* embedded = @Hateoas\Embedded(
* "expr(object.b)",
* exclusion = @Hateoas\Exclusion(maxDepth=1)
* )
* )
*/
class Gh236Foo
{
/**
* @Serializer\Expose()
* @Serializer\MaxDepth(1)
*/
public $a;

/**
* @Serializer\Exclude()
*/
public $b;

public function __construct()
{
$this->a = new Gh236Bar();
$this->a->inner = new Gh236Bar();

$this->b = new Gh236Bar();
$this->b->xxx = 'zzz';
$this->b->inner = new Gh236Bar();
}
}
51 changes: 45 additions & 6 deletions tests/Hateoas/Tests/Serializer/JsonHalSerializerTest.php
Expand Up @@ -5,12 +5,17 @@
use Hateoas\HateoasBuilder;
use Hateoas\Model\Embedded;
use Hateoas\Model\Link;
use Hateoas\Representation\CollectionRepresentation;
use Hateoas\Serializer\JsonHalSerializer;
use Hateoas\Serializer\Metadata\RelationPropertyMetadata;
use Hateoas\Tests\Fixtures\AdrienBrault;
use Hateoas\Tests\Fixtures\Foo1;
use Hateoas\Tests\Fixtures\Foo2;
use Hateoas\Tests\Fixtures\Foo3;
use Hateoas\Tests\Fixtures\Gh236Foo;
use Hateoas\Tests\TestCase;
use JMS\Serializer\SerializationContext;
use Prophecy\Argument;

class JsonHalSerializerTest extends TestCase
{
Expand Down Expand Up @@ -75,14 +80,16 @@ public function testSerializeEmbeddeds()
->willReturnArgument()
;
}
$contextProphecy->pushPropertyMetadata(Argument::type('Hateoas\Serializer\Metadata\RelationPropertyMetadata'))->shouldBeCalled();
$contextProphecy->popPropertyMetadata()->shouldBeCalled();

$embeddeds = array(
new Embedded('friend', array('name' => 'John')),
new Embedded('foo', array('name' => 'Bar')),
new Embedded('foo', array('name' => 'Baz')),
new Embedded('bar', array('name' => 'Foo')),
new Embedded('bar', array('name' => 'Baz')),
new Embedded('bar', array('name' => 'Buzz')),
new Embedded('friend', array('name' => 'John'), new RelationPropertyMetadata()),
new Embedded('foo', array('name' => 'Bar'), new RelationPropertyMetadata()),
new Embedded('foo', array('name' => 'Baz'), new RelationPropertyMetadata()),
new Embedded('bar', array('name' => 'Foo'), new RelationPropertyMetadata()),
new Embedded('bar', array('name' => 'Baz'), new RelationPropertyMetadata()),
new Embedded('bar', array('name' => 'Buzz'), new RelationPropertyMetadata()),
);

$expectedEmbeddedded = array(
Expand Down Expand Up @@ -269,4 +276,36 @@ public function testSerializeInlineJson()
$this->json($hateoas->serialize($foo1, 'json'))
);
}

public function testGh236()
{
$data = new CollectionRepresentation([new Gh236Foo()]);

$hateoas = HateoasBuilder::buildHateoas();

$this->assertSame(
<<<JSON
{
"_embedded": {
"items": [
{
"a": {
"xxx": "yyy"
},
"_embedded": {
"b_embed": {
"xxx": "zzz"
}
}
}
]
}
}
JSON
,
$this->json(
$hateoas->serialize($data, 'json', SerializationContext::create()->enableMaxDepthChecks())
)
);
}
}
31 changes: 31 additions & 0 deletions tests/Hateoas/Tests/Serializer/XmlHalSerializerTest.php
Expand Up @@ -3,9 +3,12 @@
namespace Hateoas\Tests\Serializer;

use Hateoas\HateoasBuilder;
use Hateoas\Representation\CollectionRepresentation;
use Hateoas\Serializer\XmlHalSerializer;
use Hateoas\Tests\Fixtures\AdrienBrault;
use Hateoas\Tests\Fixtures\Gh236Foo;
use Hateoas\Tests\TestCase;
use JMS\Serializer\SerializationContext;

class XmlHalSerializerTest extends TestCase
{
Expand Down Expand Up @@ -44,4 +47,32 @@ public function testSerializeAdrienBrault()
$hateoas->serialize($adrienBrault, 'xml')
);
}

public function testGh236()
{
$data = new CollectionRepresentation([new Gh236Foo()]);

$hateoas = HateoasBuilder::create()
->setXmlSerializer(new XmlHalSerializer())
->build();

$this->assertSame(
<<<XML
<?xml version="1.0" encoding="UTF-8"?>
<collection>
<resource rel="items">
<a>
<xxx><![CDATA[yyy]]></xxx>
</a>
<resource rel="b_embed">
<xxx><![CDATA[zzz]]></xxx>
</resource>
</resource>
</collection>
XML
,
$hateoas->serialize($data, 'xml', SerializationContext::create()->enableMaxDepthChecks())
);
}
}

0 comments on commit 7e1a233

Please sign in to comment.