Skip to content

Commit 2b6ebea

Browse files
dbufabpot
authored andcommitted
[serializer] extract normalizer tests to traits
1 parent 77f642e commit 2b6ebea

25 files changed

+1693
-1207
lines changed

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

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,89 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
3232
use ObjectToPopulateTrait;
3333
use SerializerAwareTrait;
3434

35-
const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit';
36-
const OBJECT_TO_POPULATE = 'object_to_populate';
37-
const GROUPS = 'groups';
38-
const ATTRIBUTES = 'attributes';
39-
const ALLOW_EXTRA_ATTRIBUTES = 'allow_extra_attributes';
40-
const DEFAULT_CONSTRUCTOR_ARGUMENTS = 'default_constructor_arguments';
41-
const CALLBACKS = 'callbacks';
42-
const CIRCULAR_REFERENCE_HANDLER = 'circular_reference_handler';
43-
const IGNORED_ATTRIBUTES = 'ignored_attributes';
35+
/* constants to configure the context */
36+
37+
/**
38+
* How many loops of circular reference to allow while normalizing.
39+
*
40+
* The default value of 1 means that when we encounter the same object a
41+
* second time, we consider that a circular reference.
42+
*
43+
* You can raise this value for special cases, e.g. in combination with the
44+
* max depth setting of the object normalizer.
45+
*/
46+
public const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit';
47+
48+
/**
49+
* Instead of creating a new instance of an object, update the specified object.
50+
*
51+
* If you have a nested structure, child objects will be overwritten with
52+
* new instances unless you set DEEP_OBJECT_TO_POPULATE to true.
53+
*/
54+
public const OBJECT_TO_POPULATE = 'object_to_populate';
55+
56+
/**
57+
* Only (de)normalize attributes that are in the specified groups.
58+
*/
59+
public const GROUPS = 'groups';
60+
61+
/**
62+
* Limit (de)normalize to the specified names.
63+
*
64+
* For nested structures, this list needs to reflect the object tree.
65+
*/
66+
public const ATTRIBUTES = 'attributes';
67+
68+
/**
69+
* If ATTRIBUTES are specified, and the source has fields that are not part of that list,
70+
* either ignore those attributes (true) or throw an ExtraAttributesException (false).
71+
*/
72+
public const ALLOW_EXTRA_ATTRIBUTES = 'allow_extra_attributes';
73+
74+
/**
75+
* Hashmap of default values for constructor arguments.
76+
*
77+
* The names need to match the parameter names in the constructor arguments.
78+
*/
79+
public const DEFAULT_CONSTRUCTOR_ARGUMENTS = 'default_constructor_arguments';
80+
81+
/**
82+
* Hashmap of field name => callable to normalize this field.
83+
*
84+
* The callable is called if the field is encountered with the arguments:
85+
*
86+
* - mixed $attributeValue value of this field
87+
* - object $object the whole object being normalized
88+
* - string $attributeName name of the attribute being normalized
89+
* - string $format the requested format
90+
* - array $context the serialization context
91+
*/
92+
public const CALLBACKS = 'callbacks';
93+
94+
/**
95+
* Handler to call when a circular reference has been detected.
96+
*
97+
* If you specify no handler, a CircularReferenceException is thrown.
98+
*
99+
* The method will be called with ($object, $format, $context) and its
100+
* return value is returned as the result of the normalize call.
101+
*/
102+
public const CIRCULAR_REFERENCE_HANDLER = 'circular_reference_handler';
103+
104+
/**
105+
* Skip the specified attributes when normalizing an object tree.
106+
*
107+
* This list is applied to each element of nested structures.
108+
*
109+
* Note: The behaviour for nested structures is different from ATTRIBUTES
110+
* for historical reason. Aligning the behaviour would be a BC break.
111+
*/
112+
public const IGNORED_ATTRIBUTES = 'ignored_attributes';
44113

45114
/**
46115
* @internal
47116
*/
48-
const CIRCULAR_REFERENCE_LIMIT_COUNTERS = 'circular_reference_limit_counters';
117+
protected const CIRCULAR_REFERENCE_LIMIT_COUNTERS = 'circular_reference_limit_counters';
49118

50119
protected $defaultContext = [
51120
self::ALLOW_EXTRA_ATTRIBUTES => true,

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

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,60 @@
3333
*/
3434
abstract class AbstractObjectNormalizer extends AbstractNormalizer
3535
{
36-
const ENABLE_MAX_DEPTH = 'enable_max_depth';
37-
const DEPTH_KEY_PATTERN = 'depth_%s::%s';
38-
const DISABLE_TYPE_ENFORCEMENT = 'disable_type_enforcement';
39-
const SKIP_NULL_VALUES = 'skip_null_values';
40-
const MAX_DEPTH_HANDLER = 'max_depth_handler';
41-
const EXCLUDE_FROM_CACHE_KEY = 'exclude_from_cache_key';
42-
const DEEP_OBJECT_TO_POPULATE = 'deep_object_to_populate';
36+
/**
37+
* Set to true to respect the max depth metadata on fields.
38+
*/
39+
public const ENABLE_MAX_DEPTH = 'enable_max_depth';
40+
41+
/**
42+
* How to track the current depth in the context.
43+
*/
44+
private const DEPTH_KEY_PATTERN = 'depth_%s::%s';
45+
46+
/**
47+
* While denormalizing, we can verify that types match.
48+
*
49+
* You can disable this by setting this flag to true.
50+
*/
51+
public const DISABLE_TYPE_ENFORCEMENT = 'disable_type_enforcement';
52+
53+
/**
54+
* Flag to control whether fields with the value `null` should be output
55+
* when normalizing or omitted.
56+
*/
57+
public const SKIP_NULL_VALUES = 'skip_null_values';
58+
59+
/**
60+
* Callback to allow to set a value for an attribute when the max depth has
61+
* been reached.
62+
*
63+
* If no callback is given, the attribute is skipped. If a callable is
64+
* given, its return value is used (even if null).
65+
*
66+
* The arguments are:
67+
*
68+
* - mixed $attributeValue value of this field
69+
* - object $object the whole object being normalized
70+
* - string $attributeName name of the attribute being normalized
71+
* - string $format the requested format
72+
* - array $context the serialization context
73+
*/
74+
public const MAX_DEPTH_HANDLER = 'max_depth_handler';
75+
76+
/**
77+
* Specify which context key are not relevant to determine which attributes
78+
* of an object to (de)normalize.
79+
*/
80+
public const EXCLUDE_FROM_CACHE_KEY = 'exclude_from_cache_key';
81+
82+
/**
83+
* Flag to tell the denormalizer to also populate existing objects on
84+
* attributes of the main object.
85+
*
86+
* Setting this to true is only useful if you also specify the root object
87+
* in OBJECT_TO_POPULATE.
88+
*/
89+
public const DEEP_OBJECT_TO_POPULATE = 'deep_object_to_populate';
4390

4491
private $propertyTypeExtractor;
4592
private $typesCache = [];

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,20 @@ class DeepObjectPopulateChildDummy
1919
public $foo;
2020

2121
public $bar;
22+
23+
// needed to have GetSetNormalizer consider this class as supported
24+
public function getFoo()
25+
{
26+
return $this->foo;
27+
}
28+
29+
public function setFoo($foo)
30+
{
31+
$this->foo = $foo;
32+
}
33+
34+
public function setBar($bar)
35+
{
36+
$this->bar = $bar;
37+
}
2238
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,9 @@ public function getChild()
4242
{
4343
return $this->child;
4444
}
45+
46+
public function getFoo()
47+
{
48+
return $this->foo;
49+
}
4550
}

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

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
1111
use Symfony\Component\Serializer\Tests\Fixtures\AbstractNormalizerDummy;
1212
use Symfony\Component\Serializer\Tests\Fixtures\NullableConstructorArgumentDummy;
13-
use Symfony\Component\Serializer\Tests\Fixtures\ProxyDummy;
1413
use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy;
1514
use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorNormalizer;
1615

@@ -99,18 +98,6 @@ public function testGetAllowedAttributesAsObjects()
9998
$this->assertEquals([$a3, $a4], $result);
10099
}
101100

102-
public function testObjectToPopulateWithProxy()
103-
{
104-
$proxyDummy = new ProxyDummy();
105-
106-
$context = [AbstractNormalizer::OBJECT_TO_POPULATE => $proxyDummy];
107-
108-
$normalizer = new ObjectNormalizer();
109-
$normalizer->denormalize(['foo' => 'bar'], 'Symfony\Component\Serializer\Tests\Fixtures\ToBeProxyfiedDummy', null, $context);
110-
111-
$this->assertSame('bar', $proxyDummy->getFoo());
112-
}
113-
114101
public function testObjectWithStaticConstructor()
115102
{
116103
$normalizer = new StaticConstructorNormalizer();

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

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
2424
use Symfony\Component\Serializer\SerializerAwareInterface;
2525
use Symfony\Component\Serializer\SerializerInterface;
26-
use Symfony\Component\Serializer\Tests\Fixtures\DeepObjectPopulateChildDummy;
27-
use Symfony\Component\Serializer\Tests\Fixtures\DeepObjectPopulateParentDummy;
2826

2927
class AbstractObjectNormalizerTest extends TestCase
3028
{
@@ -163,58 +161,6 @@ public function testExtraAttributesException()
163161
'allow_extra_attributes' => false,
164162
]);
165163
}
166-
167-
public function testSkipNullValues()
168-
{
169-
$dummy = new Dummy();
170-
$dummy->bar = 'present';
171-
172-
$normalizer = new ObjectNormalizer();
173-
$result = $normalizer->normalize($dummy, null, [AbstractObjectNormalizer::SKIP_NULL_VALUES => true]);
174-
$this->assertSame(['bar' => 'present'], $result);
175-
}
176-
177-
public function testDeepObjectToPopulate()
178-
{
179-
$child = new DeepObjectPopulateChildDummy();
180-
$child->bar = 'bar-old';
181-
$child->foo = 'foo-old';
182-
183-
$parent = new DeepObjectPopulateParentDummy();
184-
$parent->setChild($child);
185-
186-
$context = [
187-
AbstractObjectNormalizer::OBJECT_TO_POPULATE => $parent,
188-
AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE => true,
189-
];
190-
191-
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
192-
$normalizer = new ObjectNormalizer($classMetadataFactory, null, null, new PhpDocExtractor());
193-
194-
$newChild = new DeepObjectPopulateChildDummy();
195-
$newChild->bar = 'bar-new';
196-
$newChild->foo = 'foo-old';
197-
198-
$serializer = $this->getMockBuilder(__NAMESPACE__.'\ObjectSerializerDenormalizer')->getMock();
199-
$serializer
200-
->method('supportsDenormalization')
201-
->with($this->arrayHasKey('bar'),
202-
$this->equalTo(DeepObjectPopulateChildDummy::class),
203-
$this->isNull(),
204-
$this->contains($child))
205-
->willReturn(true);
206-
$serializer->method('denormalize')->willReturn($newChild);
207-
208-
$normalizer->setSerializer($serializer);
209-
$normalizer->denormalize([
210-
'child' => [
211-
'bar' => 'bar-new',
212-
],
213-
], 'Symfony\Component\Serializer\Tests\Fixtures\DeepObjectPopulateParentDummy', null, $context);
214-
215-
$this->assertSame('bar-new', $parent->getChild()->bar);
216-
$this->assertSame('foo-old', $parent->getChild()->foo);
217-
}
218164
}
219165

220166
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer

0 commit comments

Comments
 (0)