8000 [Serializer] Add option to skip uninitialized typed properties · symfony/symfony@d129544 · GitHub
[go: up one dir, main page]

Skip to content

Commit d129544

Browse files
Georgi Georgievvuryss
authored andcommitted
[Serializer] Add option to skip uninitialized typed properties
1 parent b14fe61 commit d129544

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException;
1515
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
16+
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
1617
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
1718
use Symfony\Component\PropertyInfo\Type;
1819
use Symfony\Component\Serializer\Encoder\CsvEncoder;
@@ -58,6 +59,12 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
5859
*/
5960
public const SKIP_NULL_VALUES = 'skip_null_values';
6061

62+
/**
63+
* Flag to control whether uninitialized PHP>=7.4 typed class properties
64+
* should be excluded when normalizing.
65+
*/
66+
public const SKIP_UNINITIALIZED_VALUES = 'skip_uninitialized_values';
67+
6168
/**
6269
* Callback to allow to set a value for an attribute when the max depth has
6370
* been reached.
@@ -176,7 +183,16 @@ public function normalize($object, string $format = null, array $context = [])
176183
}
177184

178185
$attributeContext = $this->getAttributeNormalizationContext($object, $attribute, $context);
179-
$attributeValue = $this->getAttributeValue($object, $attribute, $format, $attributeContext);
186+
187+
try {
188+
$attributeValue = $this->getAttributeValue($object, $attribute, $format, $attributeContext);
189+
} catch (UninitializedPropertyException $exception) {
190+
if ($context[self::SKIP_UNINITIALIZED_VALUES] ?? $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] ?? false) {
191+
continue;
192+
}
193+
throw $exception;
194+
}
195+
180196
if ($maxDepthReached) {
181197
$attributeValue = $maxDepthHandler($attributeValue, $object, $attribute, $format, $attributeContext);
182198
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Symfony\Component\Serializer\Tests\Normalizer\Features;
4+
5+
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
6+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
7+
8+
/**
9+
* Test AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES.
10+
*
11+
* @requires PHP 7.4
12+
*/
13+
trait SkipUninitializedValuesTestTrait
14+
{
15+
abstract protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface;
16+
17+
/**
18+
* @requires PHP 7.4
19+
*/
20+
public function testSkipUninitializedValues()
21+
{
22+
$object = new TypedPropertiesObject();
23+
24+
$normalizer = $this->getNormalizerForSkipUninitializedValues();
25+
$result = $normalizer->normalize($object, null, ['skip_uninitialized_values' => true, 'groups' => ['foo']]);
26+
$this->assertSame(['initialized' => 'value'], $result);
27+
}
28+
29+
/**
30+
* @requires PHP 7.4
31+
*/
32+
public function testWithoutSkipUninitializedValues()
33+
{
34+
$object = new TypedPropertiesObject();
35+
36+
$normalizer = $this->getNormalizerForSkipUninitializedValues();
37+
$this->expectException(UninitializedPropertyException::class);
38+
$normalizer->normalize($object, null, ['groups' => ['foo']]);
39+
}
40+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symfony\Component\Serializer\Tests\Normalizer\Features;
6+
7+
use Symfony\Component\Serializer\Annotation\Groups;
8+
9+
class TypedPropertiesObject
10+
{
11+
/**
12+
* @Groups({"foo"})
13+
*/
14+
public string $unInitialized;
15+
16+
/**
17+
* @Groups({"foo"})
18+
*/
19+
public string $initialized = 'value';
20+
21+
/**
22+
* @Groups({"bar"})
23+
*/
24+
public string $initialized2 = 'value';
25+
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
use Symfony\Component\Serializer\Tests\Normalizer\Features\ObjectDummy;
5050
use Symfony\Component\Serializer\Tests\Normalizer\Features\ObjectToPopulateTestTrait;
5151
use Symfony\Component\Serializer\Tests\Normalizer\Features\SkipNullValuesTestTrait;
52+
use Symfony\Component\Serializer\Tests\Normalizer\Features\SkipUninitializedValuesTestTrait;
5253
use Symfony\Component\Serializer\Tests\Normalizer\Features\TypeEnforcementTestTrait;
5354

5455
/**
@@ -66,6 +67,7 @@ class ObjectNormalizerTest extends TestCase
6667
use MaxDepthTestTrait;
6768
use ObjectToPopulateTestTrait;
6869
use SkipNullValuesTestTrait;
70+
use SkipUninitializedValuesTestTrait;
6971
use TypeEnforcementTestTrait;
7072

7173
/**
@@ -534,6 +536,15 @@ protected function getNormalizerForSkipNullValues(): ObjectNormalizer
534536
return new ObjectNormalizer();
535537
}
536538

539+
// skip uninitialized
540+
541+
protected function getNormalizerForSkipUninitializedValues(): ObjectNormalizer
542+
{
543+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
544+
545+
return new ObjectNormalizer($classMetadataFactory);
546+
}
547+
537548
// type enforcement
538549

539550
protected function getDenormalizerForTypeEnforcement(): ObjectNormalizer

0 commit comments

Comments
 (0)
0