diff --git a/src/XmlFormatter.php b/src/XmlFormatter.php index b1b743c..f2c3f38 100644 --- a/src/XmlFormatter.php +++ b/src/XmlFormatter.php @@ -4,6 +4,8 @@ use SimpleXMLElement; use Throwable; +use function array_walk_recursive; +use function current; use function sprintf; abstract class XmlFormatter implements ResourceFormatter @@ -36,7 +38,7 @@ public function from(RestResource $resource): string )); try { $this->toSimpleXML( - $resource->body() + $this->linksOf($resource, $this->baseUri), + current($this->prepare($resource)), $xml ); return (string) $xml->asXML(); @@ -51,4 +53,22 @@ abstract protected function toSimpleXML( SimpleXMLElement $parent, bool $alreadySingularized = false ): void; + + private function prepare(RestResource $resource): array + { + return [$resource->name() => + $this->flatten($resource->body()) + + $this->linksOf($resource, $this->baseUri) + ]; + } + + private function flatten(array $body): array + { + array_walk_recursive($body, function (&$data) { + if ($data instanceof RestResource) { + $data = $this->prepare($data); + } + }); + return $body; + } } diff --git a/tests/formatting_the_resource_as_condensed_xml.php b/tests/formatting_the_resource_as_condensed_xml.php index bb10fd2..66ee478 100644 --- a/tests/formatting_the_resource_as_condensed_xml.php +++ b/tests/formatting_the_resource_as_condensed_xml.php @@ -145,6 +145,68 @@ function formatting_a_basic_resource_with_a_list_of_people() ); } + /** @test */ + function formatting_a_nested_resource() + { + $resource = new BasicResource( + 'nested-resource', + ['children' => [ + new BasicResource('child-resource', ['n' => 1], Links::none()), + new BasicResource('child-resource', ['n' => 2], Links::none()), + new BasicResource('child-resource', ['n' => 3], Links::none()), + ]], + Links::none() + ); + + $this->assertXmlStringEqualsXmlString( + ' + + + + + + + ', + $this->xml->from($resource) + ); + } + + /** @test */ + function formatting_a_twice_nested_resource() + { + $resource = new BasicResource( + 'nested-resource', + ['children' => [ + new BasicResource( + 'child-resource', + ['grandchildren' => [ + new MinimalResource(['foo' => 'bar']) + ]], + Links::none() + ), + ]], + Links::none() + ); + + $this->assertXmlStringEqualsXmlString( + ' + + + + + + + + + + + + + ', + $this->xml->from($resource) + ); + } + /** @test */ function formatting_a_resource_with_a_link() { @@ -442,6 +504,59 @@ function formatting_a_resource_with_a_lot_of_nested_elements() ); } + /** @test */ + function formatting_a_nested_resource_where_the_children_have_links() + { + $resource = new BasicResource( + 'nested-resource', + ['children' => [ + new BasicResource('child-resource', ['n' => 1], Links::provide( + Link::to('foo', Type::get('Foo')) + )), + new BasicResource('child-resource', ['n' => 2], Links::provide( + Link::to('foo', Type::get('Foo')) + )), + new BasicResource('child-resource', ['n' => 3], Links::provide( + Link::to('foo', Type::get('Foo')) + )), + ]], + Links::provide(Link::to('bar', Type::get('Bar'))) + ); + + $this->assertXmlStringEqualsXmlString( + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + ', + $this->xml->from($resource) + ); + } + /** @test */ function not_formatting_resources_with_circular_references() { diff --git a/tests/formatting_the_resource_as_xml.php b/tests/formatting_the_resource_as_xml.php index 13393e2..f0868c9 100644 --- a/tests/formatting_the_resource_as_xml.php +++ b/tests/formatting_the_resource_as_xml.php @@ -158,6 +158,70 @@ function formatting_a_basic_resource_with_a_list_of_people() ); } + /** @test */ + function formatting_a_nested_resource() + { + $resource = new BasicResource( + 'nested-resource', + ['children' => [ + new BasicResource('child-resource', ['n' => 1], Links::none()), + new BasicResource('child-resource', ['n' => 2], Links::none()), + new BasicResource('child-resource', ['n' => 3], Links::none()), + ]], + Links::none() + ); + + $this->assertXmlStringEqualsXmlString( + ' + + + 1 + 2 + 3 + + ', + $this->xml->from($resource) + ); + } + + /** @test */ + function formatting_a_twice_nested_resource() + { + $resource = new BasicResource( + 'nested-resource', + ['children' => [ + new BasicResource( + 'child-resource', + ['grandchildren' => [ + new MinimalResource(['foo' => 'bar']) + ]], + Links::none() + ), + ]], + Links::none() + ); + + $this->assertXmlStringEqualsXmlString( + ' + + + + + + + + bar + + + + + + + ', + $this->xml->from($resource) + ); + } + /** @test */ function formatting_a_resource_with_a_link() { @@ -579,6 +643,72 @@ function formatting_a_resource_with_a_lot_of_nested_elements() ); } + /** @test */ + function formatting_a_nested_resource_where_the_children_have_links() + { + $resource = new BasicResource( + 'nested-resource', + ['children' => [ + new BasicResource('child-resource', ['n' => 1], Links::provide( + Link::to('foo', Type::get('Foo')) + )), + new BasicResource('child-resource', ['n' => 2], Links::provide( + Link::to('foo', Type::get('Foo')) + )), + new BasicResource('child-resource', ['n' => 3], Links::provide( + Link::to('foo', Type::get('Foo')) + )), + ]], + Links::provide(Link::to('bar', Type::get('Bar'))) + ); + + $this->assertXmlStringEqualsXmlString( + ' + + + + 1 + + + server/foo + Foo + GET + + + + + 2 + + + server/foo + Foo + GET + + + + + 3 + + + server/foo + Foo + GET + + + + + + + server/bar + Bar + GET + + + ', + $this->xml->from($resource) + ); + } + /** @test */ function not_formatting_resources_with_circular_references() {