feature #35235 [Serializer] Added scalar denormalization (a-menshchikov)
This PR was merged into the 5.1-dev branch.
Discussion
----------
[Serializer] Added scalar denormalization
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| Deprecations? | no
| Tickets | Fix #33784
| License | MIT
Was added an ability to deserialize scalar data (single or array).
Commits
-------
dad04d0adf
Added scalar denormalization in Serializer + added scalar normalization tests
This commit is contained in:
commit
ddc016988e
@ -1,6 +1,11 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
5.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added support for scalar values denormalization
|
||||||
|
|
||||||
5.0.0
|
5.0.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@ -12,7 +17,7 @@ CHANGELOG
|
|||||||
`AbstractNormalizer::$camelizedAttributes`, `AbstractNormalizer::setCircularReferenceLimit()`,
|
`AbstractNormalizer::$camelizedAttributes`, `AbstractNormalizer::setCircularReferenceLimit()`,
|
||||||
`AbstractNormalizer::setCircularReferenceHandler()`, `AbstractNormalizer::setCallbacks()` and
|
`AbstractNormalizer::setCircularReferenceHandler()`, `AbstractNormalizer::setCallbacks()` and
|
||||||
`AbstractNormalizer::setIgnoredAttributes()`, use the default context instead.
|
`AbstractNormalizer::setIgnoredAttributes()`, use the default context instead.
|
||||||
* removed `AbstractObjectNormalizer::$maxDepthHandler` and `AbstractObjectNormalizer::setMaxDepthHandler()`,
|
* removed `AbstractObjectNormalizer::$maxDepthHandler` and `AbstractObjectNormalizer::setMaxDepthHandler()`,
|
||||||
use the default context instead.
|
use the default context instead.
|
||||||
* removed `XmlEncoder::setRootNodeName()` & `XmlEncoder::getRootNodeName()`, use the default context instead.
|
* removed `XmlEncoder::setRootNodeName()` & `XmlEncoder::getRootNodeName()`, use the default context instead.
|
||||||
* removed individual encoders/normalizers options as constructor arguments.
|
* removed individual encoders/normalizers options as constructor arguments.
|
||||||
|
@ -46,6 +46,13 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
|||||||
*/
|
*/
|
||||||
class Serializer implements SerializerInterface, ContextAwareNormalizerInterface, ContextAwareDenormalizerInterface, ContextAwareEncoderInterface, ContextAwareDecoderInterface
|
class Serializer implements SerializerInterface, ContextAwareNormalizerInterface, ContextAwareDenormalizerInterface, ContextAwareEncoderInterface, ContextAwareDecoderInterface
|
||||||
{
|
{
|
||||||
|
private const SCALAR_TYPES = [
|
||||||
|
'int' => true,
|
||||||
|
'bool' => true,
|
||||||
|
'float' => true,
|
||||||
|
'string' => true,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Encoder\ChainEncoder
|
* @var Encoder\ChainEncoder
|
||||||
*/
|
*/
|
||||||
@ -177,6 +184,14 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface
|
|||||||
*/
|
*/
|
||||||
public function denormalize($data, string $type, string $format = null, array $context = [])
|
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||||
{
|
{
|
||||||
|
if (isset(self::SCALAR_TYPES[$type])) {
|
||||||
|
if (!('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) {
|
if (!$this->normalizers) {
|
||||||
throw new LogicException('You must register at least one normalizer to be able to denormalize objects.');
|
throw new LogicException('You must register at least one normalizer to be able to denormalize objects.');
|
||||||
}
|
}
|
||||||
@ -201,7 +216,7 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface
|
|||||||
*/
|
*/
|
||||||
public function supportsDenormalization($data, string $type, string $format = null, array $context = [])
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@ use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
|
|||||||
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
||||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||||
|
use Symfony\Component\Serializer\Exception\LogicException;
|
||||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
|
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
|
||||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
|
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
|
||||||
@ -488,6 +489,86 @@ class SerializerTest extends TestCase
|
|||||||
(new Serializer())->normalize(tmpfile());
|
(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()
|
private function serializerWithClassDiscriminator()
|
||||||
{
|
{
|
||||||
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
||||||
|
Reference in New Issue
Block a user