Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e0920a2

Browse files
committed
ScalarDenormalizer handle XML/CSV
1 parent 36f7fab commit e0920a2

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

src/Symfony/Component/Serializer/Normalizer/ScalarDenormalizer.php

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@
1212
namespace Symfony\Component\Serializer\Normalizer;
1313

1414
use Symfony\Component\PropertyInfo\Type;
15+
use Symfony\Component\Serializer\Encoder\CsvEncoder;
1516
use Symfony\Component\Serializer\Encoder\JsonEncoder;
17+
use Symfony\Component\Serializer\Encoder\XmlEncoder;
1618
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
1719
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
1820

1921
final class ScalarDenormalizer implements DenormalizerInterface, CacheableSupportsMethodInterface
2022
{
2123
public const SCALAR_TYPES = [
22-
'int' => true,
23-
'bool' => true,
24-
'float' => true,
25-
'string' => true,
24+
Type::BUILTIN_TYPE_INT => true,
25+
Type::BUILTIN_TYPE_BOOL => true,
26+
Type::BUILTIN_TYPE_FLOAT => true,
27+
Type::BUILTIN_TYPE_STRING => true,
2628
];
2729

2830
/**
@@ -34,6 +36,45 @@ public function denormalize($data, string $type, string $format = null, array $c
3436
throw new InvalidArgumentException(sprintf('Data expected to be of one of the types in "%s" ("%s" given).', implode(', ', array_keys(self::SCALAR_TYPES)), get_debug_type($data)));
3537
}
3638

39+
// In XML and CSV all basic datatypes are represented as strings, it is e.g. not possible to determine,
40+
// if a value is meant to be a string, float, int or a boolean value from the serialized representation.
41+
// That's why we have to transform the values, if one of these non-string basic datatypes is expected.
42+
if (\is_string($data) && (XmlEncoder::FORMAT === $format || CsvEncoder::FORMAT === $format)) {
43+
switch ($type) {
44+
case Type::BUILTIN_TYPE_BOOL:
45+
// according to https://www.w3.org/TR/xmlschema-2/#boolean, valid representations are "false", "true", "0" and "1"
46+
if ('false' === $data || '0' === $data) {
47+
return false;
48+
}
49+
if ('true' === $data || '1' === $data) {
50+
return true;
51+
}
52+
53+
throw new NotNormalizableValueException(sprintf('Data expected to be of type "%s" ("%s" given).', $type, $data));
54+
case Type::BUILTIN_TYPE_INT:
55+
if (ctype_digit($data) || '-' === $data[0] && ctype_digit(substr($data, 1))) {
56+
return (int) $data;
57+
}
58+
59+
throw new NotNormalizableValueException(sprintf('Data expected to be of type "%s" ("%s" given).', $type, $data));
60+
case Type::BUILTIN_TYPE_FLOAT:
61+
if (is_numeric($data)) {
62+
return (float) $data;
63+
}
64+
65+
switch ($data) {
66+
case 'NaN':
67+
return \NAN;
68+
case 'INF':
69+
return \INF;
70+
case '-INF':
71+
return -\INF;
72+
default:
73+
throw new NotNormalizableValueException(sprintf('Data expected to be of type "%s" ("%s" given).', $type, $data));
74+
}
75+
}
76+
}
77+
3778
// JSON only has a Number type corresponding to both int and float PHP types.
3879
// PHP's json_encode, JavaScript's JSON.stringify, Go's json.Marshal as well as most other JSON encoders convert
3980
// floating-point numbers like 12.0 to 12 (the decimal part is dropped when possible).

src/Symfony/Component/Serializer/Tests/SerializerTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
use Symfony\Component\PropertyAccess\PropertyAccessor;
1717
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1818
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
19+
use Symfony\Component\Serializer\Encoder\CsvEncoder;
1920
use Symfony\Component\Serializer\Encoder\JsonEncoder;
21+
use Symfony\Component\Serializer\Encoder\XmlEncoder;
2022
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
2123
use Symfony\Component\Serializer\Exception\LogicException;
2224
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
@@ -631,6 +633,7 @@ public function testDeserializeScalarFromJson()
631633
$serializer = new Serializer([new ScalarDenormalizer()], ['json' => new JsonEncoder()]);
632634

633635
$this->assertSame(42, $serializer->deserialize('42', 'int', 'json'));
636+
$this->assertSame(-42, $serializer->deserialize('-42', 'int', 'json'));
634637
$this->assertTrue($serializer->deserialize('true', 'bool', 'json'));
635638
$this->assertSame(3.14, $serializer->deserialize('3.14', 'float', 'json'));
636639
$this->assertSame(3.14, $serializer->deserialize('31.4e-1', 'float', 'json'));
@@ -639,6 +642,54 @@ public function testDeserializeScalarFromJson()
639642
$this->assertSame('@Ca$e%', $serializer->deserialize('"@Ca$e%"', 'string', 'json'));
640643
}
641644

645+
public function testDeserializeScalarFromXml()
646+
{
647+
$serializer = new Serializer([new ScalarDenormalizer()], ['xml' => new XmlEncoder()]);
648+
649+
$deserialize = function ($value, string $type) use ($serializer) {
650+
return $serializer->deserialize("<?xml version='1.0'?>\n<tag>$value</tag>", $type, 'xml');
651+
};
652+
653+
$this->assertSame(42, $deserialize('42', 'int'));
654+
$this->assertSame(-42, $deserialize('-42', 'int'));
655+
$this->assertTrue($deserialize('true', 'bool'));
656+
$this->assertTrue($deserialize('1', 'bool'));
657+
$this->assertFalse($deserialize('false', 'bool'));
658+
$this->assertFalse($deserialize('0', 'bool'));
659+
$this->assertSame(3.14, $deserialize('3.14', 'float'));
660+
$this->assertSame(3.14, $deserialize('31.4e-1', 'float'));
661+
$this->assertSame(3.0, $deserialize('3', 'float')); // '3' === json_encode(3.0)
662+
$this->assertNan($deserialize('NaN', 'float'));
663+
$this->assertSame(\INF, $deserialize('INF', 'float'));
664+
$this->assertSame(-\INF, $deserialize('-INF', 'float'));
665+
$this->assertSame(' spaces ', $deserialize(' spaces ', 'string'));
666+
$this->assertSame('@Ca$e%', $deserialize('@Ca$e%', 'string'));
667+
}
668+
669+
public function testDeserializeScalarFromCsv()
670+
{
671+
$serializer = new Serializer([new ArrayDenormalizer(), new ScalarDenormalizer()], ['csv' => new CsvEncoder()]);
672+
673+
$deserialize = function ($value, string $type) use ($serializer) {
674+
return $serializer->deserialize("0\n$value\n", $type, 'csv', [CsvEncoder::AS_COLLECTION_KEY => false]);
675+
};
676+
677+
$this->assertSame(42, $deserialize('42', 'int[]')[0]);
678+
$this->assertSame(-42, $deserialize('-42', 'int[]')[0]);
679+
$this->assertTrue($deserialize('true', 'bool[]')[0]);
680+
$this->assertTrue($deserialize('1', 'bool[]')[0]);
681+
$this->assertFalse($deserialize('false', 'bool[]')[0]);
682+
$this->assertFalse($deserialize('0', 'bool[]')[0]);
683+
$this->assertSame(3.14, $deserialize('3.14', 'float[]')[0]);
684+
$this->assertSame(3.14, $deserialize('31.4e-1', 'float[]')[0]);
685+
$this->assertSame(3.0, $deserialize('3', 'float[]')[0]); // '3' === json_encode(3.0)
686+
$this->assertNan($deserialize('NaN', 'float[]')[0]);
687+
$this->assertSame(\INF, $deserialize('INF', 'float[]')[0]);
688+
$this->assertSame(-\INF, $deserialize('-INF', 'float[]')[0]);
689+
$this->assertSame(' spaces ', $deserialize(' spaces ', 'string[]')[0]);
690+
$this->assertSame('@Ca$e%', $deserialize('@Ca$e%', 'string[]')[0]);
691+
}
692+
642693
public function testDeserializeLegacyScalarType()
643694
{
644695
$this->expectException(NotNormalizableValueException::class);

0 commit comments

Comments
 (0)