Skip to content

Commit

Permalink
Add condensed xml formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
Stratadox committed Jan 29, 2020
1 parent 1c6f24e commit b3bacf7
Show file tree
Hide file tree
Showing 3 changed files with 629 additions and 0 deletions.
72 changes: 72 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,39 @@ $this->assertXmlStringEqualsXmlString(
);
```

## Example (condensed xml)
The same resource again, now formatted as xml with less verbosity:

```php
<?php

use Stratadox\RestResource\BasicResource;
use Stratadox\RestResource\CondensedXmlFormatter;
use Stratadox\RestResource\Test\Fixture\TestRelation;
use Stratadox\RestResource\Link;
use Stratadox\RestResource\Links;

$xml = new CondensedXmlFormatter('https://a.server.somewhere/');

$resource = new BasicResource(
'hateoas-resource',
['foo' => 'bar'],
Links::provide(
Link::to('foo/1', new TestRelation('Foo'))
)
);

$this->assertXmlStringEqualsXmlString(
'<?xml version="1.0"?>
<hateoas-resource foo="bar">
<links>
<link href="server/foo/1" rel="Foo" type="GET" />
</links>
</hateoas-resource>',
$xml->from($resource)
);
```

## Singularisation
Formatting an xml document based on just an array structure is slightly more
challenging than converting to json.
Expand Down Expand Up @@ -133,6 +166,13 @@ However, we'd expect from xml something in the genre of:
</person>
</people>
```
Or
```xml
<people>
<person id="1" name="Alice" />
<person id="2" name="Bob" />
</people>
```

By default, the xml formatter uses [inflection](https://github.com/ICanBoogie/Inflector)
to transform plurals into singular versions. As such, the aforementioned php
Expand Down Expand Up @@ -208,3 +248,35 @@ $this->assertXmlStringEqualsXmlString(
$xml->from($resource)
);
```
Or, with less verbosity:

```php
<?php

use Stratadox\RestResource\BasicResource;
use Stratadox\RestResource\BasicSingularizer;
use Stratadox\RestResource\CondensedXmlFormatter;
use Stratadox\RestResource\Links;

$xml = new CondensedXmlFormatter('/', new BasicSingularizer());

$resource = new BasicResource(
'people-resource',
['people' => [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
]],
Links::none()
);

$this->assertXmlStringEqualsXmlString(
'<?xml version="1.0"?>
<people-resource>
<people>
<item id="1" name="Alice" />
<item id="2" name="Bob" />
</people>
</people-resource>',
$xml->from($resource)
);
```
79 changes: 79 additions & 0 deletions src/CondensedXmlFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php declare(strict_types=1);

namespace Stratadox\RestResource;

use SimpleXMLElement;
use Throwable;
use function is_array;
use function is_numeric;
use function sprintf;
use function str_replace;

final class CondensedXmlFormatter implements ResourceFormatter
{
use LinkRetrieval;

/** @var string */
private $baseUri;
/** @var Singularizer */
private $singularizer;

public function __construct(string $baseUri, Singularizer $singularizer = null)
{
$this->baseUri = $baseUri;
$this->singularizer = $singularizer ?: BoogieSingularizer::default();
}

public static function in(
string $locale,
string $baseUri
): ResourceFormatter {
return new self($baseUri, BoogieSingularizer::in($locale));
}

public function from(RestResource $resource): string
{
$xml = new SimpleXMLElement(sprintf(
'<?xml version="1.0"?><%s />',
$resource->name()
));
try {
$this->toSimpleXML(
$resource->body() + $this->linksOf($resource, $this->baseUri),
$xml
);
return (string) $xml->asXML();
} catch (Throwable $exception) {
throw CannotFormatXml::because($resource, $exception);
}
}

private function toSimpleXML(
array $input,
SimpleXMLElement $parent,
bool $alreadySingularized = false
): void {
foreach ($input as $key => $value) {

if (is_numeric($key)) {
$name = $alreadySingularized ?
'item' : $this->singularizer->convert($parent->getName());
$singularized = true;
} else {
$name = str_replace(['<', '>'], '', (string) $key);
$singularized = false;
}

if (is_array($value)) {
$node = $parent->addChild($name);
$this->toSimpleXML($value, $node, $singularized);
} elseif ($singularized) {
$child = $parent->addChild($name);
$child->addAttribute('value', (string) $value);
} else {
$parent->addAttribute($name, (string) $value);
}

}
}
}
Loading

0 comments on commit b3bacf7

Please sign in to comment.