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

Skip to content

Commit 4901953

Browse files
committed
Fix denormalizing empty string into object|null parameter
1 parent dad8af3 commit 4901953

File tree

4 files changed

+48
-48
lines changed

4 files changed

+48
-48
lines changed

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

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ abstract protected function extractAttributes(object $object, string $format = n
334334

335335
/**
336336
* Gets the attribute value.
337+
*
338+
* @return mixed
337339
*/
338340
abstract protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []);
339341

@@ -462,8 +464,6 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
462464
return null;
463465
}
464466

465-
$isUnionTypeOrNullable = $isUnionTypeOrNullable ?: $type->isNullable();
466-
$hasNonObjectType = $hasNonObjectType ?: Type::BUILTIN_TYPE_OBJECT !== $type->getBuiltinType();
467467
$collectionValueType = $type->isCollection() ? $type->getCollectionValueTypes()[0] ?? null : null;
468468

469469
// Fix a collection that contains the only one element
@@ -488,7 +488,11 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
488488
return [];
489489
}
490490

491-
if ($type->isNullable() && \in_array($builtinType, [Type::BUILTIN_TYPE_BOOL, Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_FLOAT], true)) {
491+
if (Type::BUILTIN_TYPE_STRING === $builtinType) {
492+
return '';
493+
}
494+
495+
if ($type->isNullable()) {
492496
return null;
493497
}
494498
}
@@ -598,15 +602,15 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
598602
throw $e;
599603
}
600604
} catch (ExtraAttributesException $e) {
601-
if (!$isUnionTypeOrNullable) {
605+
if (!$isUnionType) {
602606
throw $e;
603607
}
604608

605609
if (!$extraAttributesException) {
606610
$extraAttributesException = $e;
607611
}
608612
} catch (MissingConstructorArgumentsException $e) {
609-
if (!$isUnionTypeOrNullable) {
613+
if (!$isUnionType) {
610614
throw $e;
611615
}
612616

@@ -616,10 +620,6 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
616620
}
617621
}
618622

619-
if ('' === $data && $isUnionTypeOrNullable && !$hasNonObjectType && (XmlEncoder::FORMAT === $format || CsvEncoder::FORMAT === $format)) {
620-
return null;
621-
}
622-
623623
if ($extraAttributesException) {
624624
throw $extraAttributesException;
625625
}
@@ -628,10 +628,6 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
628628
throw $missingConstructorArgumentException;
629629
}
630630

631-
if (!$isUnionType && isset($e)) {
632-
throw $e;
633-
}
634-
635631
if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) {
636632
return $data;
637633
}

src/Symfony/Component/Serializer/Tests/Fixtures/NotNormalizableDummy.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function __construct()
2424
{
2525
}
2626

27-
public function denormalize(DenormalizerInterface $denormalizer, float|int|bool|array|string $data, string $format = null, array $context = [])
27+
public function denormalize(DenormalizerInterface $denormalizer, $data, string $format = null, array $context = [])
2828
{
2929
throw new NotNormalizableValueException();
3030
}

src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
use Doctrine\Common\Annotations\AnnotationReader;
1515
use PHPUnit\Framework\TestCase;
1616
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
17+
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
18+
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
1719
use Symfony\Component\PropertyInfo\Type;
1820
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
1921
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
2022
use Symfony\Component\Serializer\Exception\LogicException;
23+
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
2124
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
2225
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
2326
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
@@ -29,6 +32,7 @@
2932
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
3033
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
3134
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
35+
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
3236
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
3337
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
3438
use Symfony\Component\Serializer\Serializer;
@@ -39,6 +43,9 @@
3943
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\AbstractDummySecondChild;
4044
use Symfony\Component\Serializer\Tests\Fixtures\DummyFirstChildQuux;
4145
use Symfony\Component\Serializer\Tests\Fixtures\DummySecondChildQuux;
46+
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithNotNormalizable;
47+
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithObjectOrBool;
48+
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithObjectOrNull;
4249

4350
class AbstractObjectNormalizerTest extends TestCase
4451
{
@@ -444,6 +451,36 @@ public function testNormalizeEmptyObject()
444451
$normalizedData = $normalizer->normalize(new EmptyDummy(), 'any', ['preserve_empty_objects' => true]);
445452
$this->assertEquals(new \ArrayObject(), $normalizedData);
446453
}
454+
455+
public function testDenormalizeUntypedFormat()
456+
{
457+
$serializer = new Serializer([new ObjectNormalizer(null, null, null, new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
458+
$actual = $serializer->denormalize(['value' => ''], DummyWithObjectOrNull::class, 'xml');
459+
460+
$this->assertEquals(new DummyWithObjectOrNull(null), $actual);
461+
}
462+
463+
public function testDenormalizeUntypedFormatNotNormalizable()
464+
{
465+
$this->expectException(NotNormalizableValueException::class);
466+
$serializer = new Serializer([new CustomNormalizer(), new ObjectNormalizer(null, null, null, new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
467+
$serializer->denormalize(['value' => 'test'], DummyWithNotNormalizable::class, 'xml');
468+
}
469+
470+
public function testDenormalizeUntypedFormatMissingArg()
471+
{
472+
$this->expectException(MissingConstructorArgumentsException::class);
473+
$serializer = new Serializer([new ObjectNormalizer(null, null, null, new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
474+
$serializer->denormalize(['value' => 'invalid'], DummyWithObjectOrNull::class, 'xml');
475+
}
476+
477+
public function testDenormalizeUntypedFormatScalar()
478+
{
479+
$serializer = new Serializer([new ObjectNormalizer(null, null, null, new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
480+
$actual = $serializer->denormalize(['value' => 'false'], DummyWithObjectOrBool::class, 'xml');
481+
482+
$this->assertEquals(new DummyWithObjectOrBool(false), $actual);
483+
}
447484
}
448485

449486
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer

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

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
2525
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
2626
use Symfony\Component\Serializer\Exception\LogicException;
27-
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
2827
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
2928
use Symfony\Component\Serializer\Exception\PartialDenormalizationException;
3029
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
@@ -64,8 +63,6 @@
6463
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
6564
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumConstructor;
6665
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumProperty;
67-
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithNotNormalizable;
68-
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithObjectOrBool;
6966
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithObjectOrNull;
7067
use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy;
7168
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
@@ -825,42 +822,12 @@ public function testFalseBuiltInTypes()
825822

826823
public function testDeserializeUntypedFormat()
827824
{
828-
$serializer = new Serializer([new ObjectNormalizer(propertyTypeExtractor: new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))], ['csv' => new CsvEncoder()]);
825+
$serializer = new Serializer([new ObjectNormalizer(null, null, null, new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))], ['csv' => new CsvEncoder()]);
829826
$actual = $serializer->deserialize('value'.\PHP_EOL.',', DummyWithObjectOrNull::class, 'csv', [CsvEncoder::AS_COLLECTION_KEY => false]);
830827

831828
$this->assertEquals(new DummyWithObjectOrNull(null), $actual);
832829
}
833830

834-
public function testDenormalizeUntypedFormat()
835-
{
836-
$serializer = new Serializer([new ObjectNormalizer(propertyTypeExtractor: new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
837-
$actual = $serializer->denormalize(['value' => ''], DummyWithObjectOrNull::class, 'xml');
838-
839-
$this->assertEquals(new DummyWithObjectOrNull(null), $actual);
840-
}
841-
842-
public function testDenormalizeUntypedFormatNotNormalizable()
843-
{
844-
$this->expectException(NotNormalizableValueException::class);
845-
$serializer = new Serializer([new CustomNormalizer(), new ObjectNormalizer(propertyTypeExtractor: new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
846-
$serializer->denormalize(['value' => 'test'], DummyWithNotNormalizable::class, 'xml');
847-
}
848-
849-
public function testDenormalizeUntypedFormatMissingArg()
850-
{
851-
$this->expectException(MissingConstructorArgumentsException::class);
852-
$serializer = new Serializer([new ObjectNormalizer(propertyTypeExtractor: new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
853-
$serializer->denormalize(['value' => 'invalid'], DummyWithObjectOrNull::class, 'xml');
854-
}
855-
856-
public function testDenormalizeUntypedFormatScalar()
857-
{
858-
$serializer = new Serializer([new ObjectNormalizer(propertyTypeExtractor: new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]);
859-
$actual = $serializer->denormalize(['value' => 'false'], DummyWithObjectOrBool::class, 'xml');
860-
861-
$this->assertEquals(new DummyWithObjectOrBool(false), $actual);
862-
}
863-
864831
private function serializerWithClassDiscriminator()
865832
{
866833
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));

0 commit comments

Comments
 (0)