Skip to content

Commit 01ef10f

Browse files
committed
Merge branch '2.8' into 3.0
* 2.8: Typo fix [WebProfiler] Fixed sf-minitoolbar height [2.3] Static Code Analysis for Components [Serializer] Use $context['cache_key'] to enhance caching Fixed erroneous deprecation notice for extended Interfaces [Routing] cs fix Added support \IteratorAggregate for UniqueEntityValidator Update AbstractChoiceListTest.php Fix #17306 Paths with % in it are note allowed (like urlencoded) Use proper class to fetch $versionStrategy property Added sort order SORT_STRING for params in UriSigner Remove normalizer cache in Serializer class [Serializer] ObjectNormalizer: context can contain not serializable data
2 parents f40b350 + 88ad9e4 commit 01ef10f

File tree

4 files changed

+116
-23
lines changed

4 files changed

+116
-23
lines changed

Normalizer/ObjectNormalizer.php

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*/
2727
class ObjectNormalizer extends AbstractNormalizer
2828
{
29-
private static $attributesCache = array();
29+
private $attributesCache = array();
3030

3131
/**
3232
* @var PropertyAccessorInterface
@@ -55,6 +55,9 @@ public function supportsNormalization($data, $format = null)
5555
*/
5656
public function normalize($object, $format = null, array $context = array())
5757
{
58+
if (!isset($context['cache_key'])) {
59+
$context['cache_key'] = $this->getCacheKey($context);
60+
}
5861
if ($this->isCircularReference($object, $context)) {
5962
return $this->handleCircularReference($object);
6063
}
@@ -104,6 +107,9 @@ public function supportsDenormalization($data, $type, $format = null)
104107
*/
105108
public function denormalize($data, $class, $format = null, array $context = array())
106109
{
110+
if (!isset($context['cache_key'])) {
111+
$context['cache_key'] = $this->getCacheKey($context);
112+
}
107113
$allowedAttributes = $this->getAllowedAttributes($class, $context, true);
108114
$normalizedData = $this->prepareForDenormalization($data);
109115

@@ -130,28 +136,59 @@ public function denormalize($data, $class, $format = null, array $context = arra
130136
return $object;
131137
}
132138

139+
private function getCacheKey(array $context)
140+
{
141+
try {
142+
return md5(serialize($context));
143+
} catch (\Exception $exception) {
144+
// The context cannot be serialized, skip the cache
145+
return false;
146+
}
147+
}
148+
133149
/**
134150
* Gets and caches attributes for this class and context.
135151
*
136152
* @param object $object
137153
* @param array $context
138154
*
139-
* @return array
155+
* @return string[]
140156
*/
141157
private function getAttributes($object, array $context)
142158
{
143-
$key = sprintf('%s-%s', get_class($object), serialize($context));
159+
$class = get_class($object);
160+
$key = $class.'-'.$context['cache_key'];
144161

145-
if (isset(self::$attributesCache[$key])) {
146-
return self::$attributesCache[$key];
162+
if (isset($this->attributesCache[$key])) {
163+
return $this->attributesCache[$key];
147164
}
148165

149166
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
150167

151168
if (false !== $allowedAttributes) {
152-
return self::$attributesCache[$key] = $allowedAttributes;
169+
if ($context['cache_key']) {
170+
$this->attributesCache[$key] = $allowedAttributes;
171+
}
172+
173+
return $allowedAttributes;
174+
}
175+
176+
if (isset($this->attributesCache[$class])) {
177+
return $this->attributesCache[$class];
153178
}
154179

180+
return $this->attributesCache[$class] = $this->extractAttributes($object);
181+
}
182+
183+
/**
184+
* Extracts attributes for this class and context.
185+
*
186+
* @param object $object
187+
*
188+
* @return string[]
189+
*/
190+
private function extractAttributes($object)
191+
{
155192
// If not using groups, detect manually
156193
$attributes = array();
157194

@@ -167,9 +204,9 @@ private function getAttributes($object, array $context)
167204
continue;
168205
}
169206

170-
$name = $reflMethod->getName();
207+
$name = $reflMethod->name;
171208

172-
if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) {
209+
if (0 === strpos($name, 'get') || 0 === strpos($name, 'has')) {
173210
// getters and hassers
174211
$attributes[lcfirst(substr($name, 3))] = true;
175212
} elseif (strpos($name, 'is') === 0) {
@@ -184,9 +221,9 @@ private function getAttributes($object, array $context)
184221
continue;
185222
}
186223

187-
$attributes[$reflProperty->getName()] = true;
224+
$attributes[$reflProperty->name] = true;
188225
}
189226

190-
return self::$attributesCache[$key] = array_keys($attributes);
227+
return array_keys($attributes);
191228
}
192229
}

Serializer.php

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -187,17 +187,10 @@ private function getNormalizer($data, $format)
187187
{
188188
if ($isObject = is_object($data)) {
189189
$class = get_class($data);
190-
if (isset($this->normalizerCache[$class][$format])) {
191-
return $this->normalizerCache[$class][$format];
192-
}
193190
}
194191

195192
foreach ($this->normalizers as $normalizer) {
196193
if ($normalizer instanceof NormalizerInterface && $normalizer->supportsNormalization($data, $format)) {
197-
if ($isObject) {
198-
$this->normalizerCache[$class][$format] = $normalizer;
199-
}
200-
201194
return $normalizer;
202195
}
203196
}
@@ -214,14 +207,8 @@ private function getNormalizer($data, $format)
214207
*/
215208
private function getDenormalizer($data, $class, $format)
216209
{
217-
if (isset($this->denormalizerCache[$class][$format])) {
218-
return $this->denormalizerCache[$class][$format];
219-
}
220-
221210
foreach ($this->normalizers as $normalizer) {
222211
if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format)) {
223-
$this->denormalizerCache[$class][$format] = $normalizer;
224-
225212
return $normalizer;
226213
}
227214
}
@@ -264,6 +251,7 @@ private function normalizeObject($object, $format, array $context = array())
264251
if ($normalizer = $this->getNormalizer($object, $format)) {
265252
return $normalizer->normalize($object, $format, $context);
266253
}
254+
267255
throw new UnexpectedValueException(sprintf('Could not normalize object of type %s, no supporting normalizer found.', get_class($object)));
268256
}
269257

@@ -289,6 +277,15 @@ private function denormalizeObject($data, $class, $format, array $context = arra
289277
if ($normalizer = $this->getDenormalizer($data, $class, $format)) {
290278
return $normalizer->denormalize($data, $class, $format, $context);
291279
}
280+
281+
foreach ($this->normalizers as $normalizer) {
282+
if ($normalizer instanceof DenormalizerInterface
283+
&& $normalizer->supportsDenormalization($data, $class, $format)) {
284+
285+
return $normalizer->denormalize($data, $class, $format, $context);
286+
}
287+
}
288+
292289
throw new UnexpectedValueException(sprintf('Could not denormalize object of type %s, no supporting normalizer found.', $class));
293290
}
294291

Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,21 @@ public function testNormalizeStatic()
445445
{
446446
$this->assertEquals(array('foo' => 'K'), $this->normalizer->normalize(new ObjectWithStaticPropertiesAndMethods()));
447447
}
448+
449+
public function testNormalizeNotSerializableContext()
450+
{
451+
$objectDummy = new ObjectDummy();
452+
$expected = array(
453+
'foo' => null,
454+
'baz' => null,
455+
'fooBar' => '',
456+
'camelCase' => null,
457+
'object' => null,
458+
'bar' => null,
459+
);
460+
461+
$this->assertEquals($expected, $this->normalizer->normalize($objectDummy, null, array('not_serializable' => function () {})));
462+
}
448463
}
449464

450465
class ObjectDummy

Tests/SerializerTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,50 @@ public function testCustomNormalizerCanNormalizeCollectionsAndScalar()
9696
$this->assertNull($serializer->normalize('test'));
9797
}
9898

99+
public function testNormalizeWithSupportOnData()
100+
{
101+
$normalizer1 = $this->getMock('Symfony\Component\Serializer\Normalizer\NormalizerInterface');
102+
$normalizer1->method('supportsNormalization')
103+
->willReturnCallback(function ($data, $format) {
104+
return isset($data->test);
105+
});
106+
$normalizer1->method('normalize')->willReturn('test1');
107+
108+
$normalizer2 = $this->getMock('Symfony\Component\Serializer\Normalizer\NormalizerInterface');
109+
$normalizer2->method('supportsNormalization')
110+
->willReturn(true);
111+
$normalizer2->method('normalize')->willReturn('test2');
112+
113+
$serializer = new Serializer(array($normalizer1, $normalizer2));
114+
115+
$data = new \stdClass();
116+
$data->test = true;
117+
$this->assertEquals('test1', $serializer->normalize($data));
118+
119+
$this->assertEquals('test2', $serializer->normalize(new \stdClass()));
120+
}
121+
122+
public function testDenormalizeWithSupportOnData()
123+
{
124+
$denormalizer1 = $this->getMock('Symfony\Component\Serializer\Normalizer\DenormalizerInterface');
125+
$denormalizer1->method('supportsDenormalization')
126+
->willReturnCallback(function ($data, $type, $format) {
127+
return isset($data['test1']);
128+
});
129+
$denormalizer1->method('denormalize')->willReturn('test1');
130+
131+
$denormalizer2 = $this->getMock('Symfony\Component\Serializer\Normalizer\DenormalizerInterface');
132+
$denormalizer2->method('supportsDenormalization')
133+
->willReturn(true);
134+
$denormalizer2->method('denormalize')->willReturn('test2');
135+
136+
$serializer = new Serializer(array($denormalizer1, $denormalizer2));
137+
138+
$this->assertEquals('test1', $serializer->denormalize(array('test1' => true), 'test'));
139+
140+
$this->assertEquals('test2', $serializer->denormalize(array(), 'test'));
141+
}
142+
99143
public function testSerialize()
100144
{
101145
$serializer = new Serializer(array(new GetSetMethodNormalizer()), array('json' => new JsonEncoder()));

0 commit comments

Comments
 (0)