Skip to content
This repository has been archived by the owner on Jun 9, 2021. It is now read-only.

Commit

Permalink
Fix #5: Add XML serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
devanych committed Nov 16, 2020
1 parent 10695eb commit 1f9b85c
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 1 deletion.
4 changes: 3 additions & 1 deletion composer.json
Expand Up @@ -16,7 +16,9 @@
"source": "https://github.com/yiisoft/serializer"
},
"require": {
"php": "^7.4|^8.0"
"php": "^7.4|^8.0",
"symfony/serializer": "^5.1.8",
"symfony/property-access": "^5.1.8"
},
"require-dev": {
"phpunit/phpunit": "^9.4",
Expand Down
41 changes: 41 additions & 0 deletions src/XmlSerializer.php
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Serializer;

use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

/**
* XmlSerializer serializes data in XML format.
*/
final class XmlSerializer implements SerializerInterface
{
private Serializer $serializer;

/**
* @param string $rootTag The name of the root element.
* @param string $version The XML version.
* @param string $encoding The XML encoding.
*/
public function __construct(string $rootTag = 'response', string $version = '1.0', string $encoding = 'UTF-8')
{
$this->serializer = new Serializer([new ObjectNormalizer()], [new XmlEncoder([
XmlEncoder::ROOT_NODE_NAME => $rootTag,
XmlEncoder::VERSION => $version,
XmlEncoder::ENCODING => $encoding,
])]);
}

public function serialize($value): string
{
return $this->serializer->serialize($value, XmlEncoder::FORMAT);
}

public function unserialize(string $value)
{
return $this->serializer->decode($value, XmlEncoder::FORMAT);
}
}
52 changes: 52 additions & 0 deletions tests/TestAsset/DummyData.php
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Serializer\Tests\TestAsset;

final class DummyData
{
private string $string;
private int $int;
private float $float;
private array $array;
private bool $bool;

public function __construct(string $string, int $int, float $float, array $array, bool $bool)
{
$this->string = $string;
$this->int = $int;
$this->float = $float;
$this->array = $array;
$this->bool = $bool;
}

public function getString(): string
{
return $this->string;
}

public function getInt(): int
{
return $this->int;
}

public function getFloat(): float
{
return $this->float;
}

public function getArray(): array
{
return $this->array;
}

/**
* @param bool $asInt
* @return bool|int
*/
public function isBool(bool $asInt = false)
{
return $asInt ? (int) $this->bool : $this->bool;
}
}
17 changes: 17 additions & 0 deletions tests/TestAsset/DummyDataHelper.php
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Serializer\Tests\TestAsset;

use function preg_replace;
use function sprintf;

final class DummyDataHelper
{
public static function xml(string $data, string $version = '1.0', string $encoding = 'UTF-8'): string
{
$startLine = sprintf('<?xml version="%s" encoding="%s"?>', $version, $encoding);
return $startLine . "\n" . preg_replace('/(?!item)\s(?!key)/', '', $data) . "\n";
}
}
125 changes: 125 additions & 0 deletions tests/XmlSerializerTest.php
@@ -0,0 +1,125 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Serializer\Tests;

use stdClass;
use Yiisoft\Serializer\SerializerInterface;
use Yiisoft\Serializer\Tests\TestAsset\DummyData;
use Yiisoft\Serializer\Tests\TestAsset\DummyDataHelper;
use Yiisoft\Serializer\XmlSerializer;

final class XmlSerializerTest extends SerializerTest
{
public function getSerializer(): SerializerInterface
{
return new XmlSerializer();
}

public function serializeProvider(): array
{
return $this->dataProvider();
}

public function unserializeProvider(): array
{
return $this->dataProvider();
}

public function dataProvider(): array
{
$data = [
'int' => [1, '<response>1</response>',],
'float' => [1.1, '<response>1.1</response>',],
'string' => ['a', '<response>a</response>',],
'null' => [null, '<response/>',],
'array' => [
[
'int' => 1,
'float' => 1.1,
'string' => 'a',
'null' => null,
'without-key-1',
'without-key-2',
'nested' => [
'int' => 1,
'float' => 1.1,
'string' => 'a',
'null' => null,
'without-key-1',
'without-key-2',
]
],
<<<EOF
<response>
<int>1</int>
<float>1.1</float>
<string>a</string>
<null/>
<item key="0">without-key-1</item>
<item key="1">without-key-2</item>
<nested>
<int>1</int>
<float>1.1</float>
<string>a</string>
<null/>
<item key="0">without-key-1</item>
<item key="1">without-key-2</item>
</nested>
</response>
EOF,
],
];

foreach ($data as $key => $value) {
$value[1] = DummyDataHelper::xml($value[1]);
$data[$key] = $value;
}

return $data;
}

public function testConstructorWithPassedArguments(): void
{
$serializer = new XmlSerializer($rootTag = 'foo', $version = '2.0', $encoding = 'Windows-1252');
$this->assertSame(
DummyDataHelper::xml("<{$rootTag}/>", $version, $encoding),
$serializer->serialize([])
);
}

public function testSerializeEmptyObject(): void
{
$serializer = new XmlSerializer();
$this->assertSame(DummyDataHelper::xml('<response/>'), $serializer->serialize(new stdClass()));
}

public function testSerializeAndUnserialize(): void
{
$serializer = new XmlSerializer();
$object = new DummyData('foo', 99, 1.1, [1, 'foo' => 'bar'], false);
$xml = <<<EOF
<response>
<string>{$object->getString()}</string>
<int>{$object->getInt()}</int>
<float>{$object->getFloat()}</float>
<array>
<item key="0">1</item>
<foo>bar</foo>
</array>
<bool>{$object->isBool(true)}</bool>
</response>
EOF;
$array = [
'string' => $object->getString(),
'int' => $object->getInt(),
'float' => $object->getFloat(),
'array' => $object->getArray(),
'bool' => (string) $object->isBool(true),
];

$this->assertSame(DummyDataHelper::xml($xml), $serializer->serialize($object));
$this->assertEquals($array, $serializer->unserialize($xml));
}
}

0 comments on commit 1f9b85c

Please sign in to comment.