Skip to content

Commit

Permalink
Added scalar denormalization in Serializer + added scalar normalizati…
Browse files Browse the repository at this point in the history
…on tests
  • Loading branch information
a-menshchikov committed Jan 11, 2020
1 parent de4c45c commit 2f3eeb8
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 2 deletions.
7 changes: 6 additions & 1 deletion src/Symfony/Component/Serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

5.1.0
-----

* added support for scalar values denormalization

5.0.0
-----

Expand All @@ -12,7 +17,7 @@ CHANGELOG
`AbstractNormalizer::$camelizedAttributes`, `AbstractNormalizer::setCircularReferenceLimit()`,
`AbstractNormalizer::setCircularReferenceHandler()`, `AbstractNormalizer::setCallbacks()` and
`AbstractNormalizer::setIgnoredAttributes()`, use the default context instead.
* removed `AbstractObjectNormalizer::$maxDepthHandler` and `AbstractObjectNormalizer::setMaxDepthHandler()`,
* removed `AbstractObjectNormalizer::$maxDepthHandler` and `AbstractObjectNormalizer::setMaxDepthHandler()`,
use the default context instead.
* removed `XmlEncoder::setRootNodeName()` & `XmlEncoder::getRootNodeName()`, use the default context instead.
* removed individual encoders/normalizers options as constructor arguments.
Expand Down
17 changes: 16 additions & 1 deletion src/Symfony/Component/Serializer/Serializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
*/
class Serializer implements SerializerInterface, ContextAwareNormalizerInterface, ContextAwareDenormalizerInterface, ContextAwareEncoderInterface, ContextAwareDecoderInterface
{
private const SCALAR_TYPES = [
'int' => true,
'bool' => true,
'float' => true,
'string' => true,
];

/**
* @var Encoder\ChainEncoder
*/
Expand Down Expand Up @@ -177,6 +184,14 @@ public function normalize($data, string $format = null, array $context = [])
*/
public function denormalize($data, string $type, string $format = null, array $context = [])
{
if (isset(self::SCALAR_TYPES[$type])) {
if (false === \call_user_func('is_'.$type, $data)) {
throw new NotNormalizableValueException(sprintf('Data expected to be of type "%s" ("%s" given)', $type, \is_object($data) ? \get_class($data) : \gettype($data)));
}

return $data;
}

if (!$this->normalizers) {
throw new LogicException('You must register at least one normalizer to be able to denormalize objects.');
}
Expand All @@ -201,7 +216,7 @@ public function supportsNormalization($data, string $format = null, array $conte
*/
public function supportsDenormalization($data, string $type, string $format = null, array $context = [])
{
return null !== $this->getDenormalizer($data, $type, $format, $context);
return isset(self::SCALAR_TYPES[$type]) || null !== $this->getDenormalizer($data, $type, $format, $context);
}

/**
Expand Down
81 changes: 81 additions & 0 deletions src/Symfony/Component/Serializer/Tests/SerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
Expand Down Expand Up @@ -488,6 +489,86 @@ public function testNotNormalizableValueExceptionMessageForAResource()
(new Serializer())->normalize(tmpfile());
}

public function testNormalizeScalar()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);

$this->assertSame('42', $serializer->serialize(42, 'json'));
$this->assertSame('true', $serializer->serialize(true, 'json'));
$this->assertSame('false', $serializer->serialize(false, 'json'));
$this->assertSame('3.14', $serializer->serialize(3.14, 'json'));
$this->assertSame('3.14', $serializer->serialize(31.4e-1, 'json'));
$this->assertSame('" spaces "', $serializer->serialize(' spaces ', 'json'));
$this->assertSame('"@Ca$e%"', $serializer->serialize('@Ca$e%', 'json'));
}

public function testNormalizeScalarArray()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);

$this->assertSame('[42]', $serializer->serialize([42], 'json'));
$this->assertSame('[true,false]', $serializer->serialize([true, false], 'json'));
$this->assertSame('[3.14,3.24]', $serializer->serialize([3.14, 32.4e-1], 'json'));
$this->assertSame('[" spaces ","@Ca$e%"]', $serializer->serialize([' spaces ', '@Ca$e%'], 'json'));
}

public function testDeserializeScalar()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);

$this->assertSame(42, $serializer->deserialize('42', 'int', 'json'));
$this->assertTrue($serializer->deserialize('true', 'bool', 'json'));
$this->assertSame(3.14, $serializer->deserialize('3.14', 'float', 'json'));
$this->assertSame(3.14, $serializer->deserialize('31.4e-1', 'float', 'json'));
$this->assertSame(' spaces ', $serializer->deserialize('" spaces "', 'string', 'json'));
$this->assertSame('@Ca$e%', $serializer->deserialize('"@Ca$e%"', 'string', 'json'));
}

public function testDeserializeLegacyScalarType()
{
$this->expectException(LogicException::class);
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$serializer->deserialize('42', 'integer', 'json');
}

public function testDeserializeScalarTypeToCustomType()
{
$this->expectException(LogicException::class);
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$serializer->deserialize('"something"', Foo::class, 'json');
}

public function testDeserializeNonscalarTypeToScalar()
{
$this->expectException(NotNormalizableValueException::class);
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$serializer->deserialize('{"foo":true}', 'string', 'json');
}

public function testDeserializeInconsistentScalarType()
{
$this->expectException(NotNormalizableValueException::class);
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$serializer->deserialize('"42"', 'int', 'json');
}

public function testDeserializeScalarArray()
{
$serializer = new Serializer([new ArrayDenormalizer()], ['json' => new JsonEncoder()]);

$this->assertSame([42], $serializer->deserialize('[42]', 'int[]', 'json'));
$this->assertSame([true, false], $serializer->deserialize('[true,false]', 'bool[]', 'json'));
$this->assertSame([3.14, 3.24], $serializer->deserialize('[3.14,32.4e-1]', 'float[]', 'json'));
$this->assertSame([' spaces ', '@Ca$e%'], $serializer->deserialize('[" spaces ","@Ca$e%"]', 'string[]', 'json'));
}

public function testDeserializeInconsistentScalarArray()
{
$this->expectException(NotNormalizableValueException::class);
$serializer = new Serializer([new ArrayDenormalizer()], ['json' => new JsonEncoder()]);
$serializer->deserialize('["42"]', 'int[]', 'json');
}

private function serializerWithClassDiscriminator()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
Expand Down

0 comments on commit 2f3eeb8

Please sign in to comment.