11
11
12
12
namespace Symfony \Component \Serializer \Normalizer ;
13
13
14
+ use Symfony \Component \Serializer \Exception \CircularReferenceException ;
14
15
use Symfony \Component \Serializer \Exception \InvalidArgumentException ;
15
16
use Symfony \Component \Serializer \Exception \RuntimeException ;
16
17
33
34
* takes place.
34
35
*
35
36
* @author Nils Adermann <naderman@naderman.de>
37
+ * @author Kévin Dunglas <dunglas@gmail.com>
36
38
*/
37
39
class GetSetMethodNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface
38
40
{
41
+ protected $ circularReferenceLimit = 1 ;
42
+ protected $ circularReferenceHandler ;
39
43
protected $ callbacks = array ();
40
44
protected $ ignoredAttributes = array ();
41
45
protected $ camelizedAttributes = array ();
42
46
47
+ /**
48
+ * Set circular reference limit.
49
+ *
50
+ * @param $circularReferenceLimit limit of recurrences
51
+ * @return GetSetMethodNormalizer
52
+ */
53
+ public function setCircularReferenceLimit ($ circularReferenceLimit )
54
+ {
55
+ $ this ->circularReferenceLimit = $ circularReferenceLimit ;
56
+
57
+ return $ this ;
58
+ }
59
+
60
+ /**
61
+ * Set circular reference handler.
62
+ *
63
+ * @param callable $circularReferenceHandler
64
+ * @return GetSetMethodNormalizer
65
+ * @throws InvalidArgumentException
66
+ */
67
+ public function setCircularReferenceHandler ($ circularReferenceHandler )
68
+ {
69
+ if (!is_callable ($ circularReferenceHandler )) {
70
+ throw new InvalidArgumentException ('The given circular reference handler is not callable. ' );
71
+ }
72
+
73
+ $ this ->circularReferenceHandler = $ circularReferenceHandler ;
74
+
75
+ return $ this ;
76
+ }
77
+
43
78
/**
44
79
* Set normalization callbacks.
45
80
*
@@ -94,6 +129,21 @@ public function setCamelizedAttributes(array $camelizedAttributes)
94
129
*/
95
130
public function normalize ($ object , $ format = null , array $ context = array ())
96
131
{
132
+ $ objectHash = spl_object_hash ($ object );
133
+ if (isset ($ context ['circular_reference_limit ' ][$ objectHash ])) {
134
+ if ($ context ['circular_reference_limit ' ][$ objectHash ] >= $ this ->circularReferenceLimit ) {
135
+ if ($ this ->circularReferenceHandler ) {
136
+ return call_user_func ($ this ->circularReferenceHandler , $ object );
137
+ }
138
+
139
+ throw new CircularReferenceException (sprintf ('A circular reference has been detected (configured limit: %d). ' , $ this ->circularReferenceLimit ));
140
+ }
141
+
142
+ $ context ['circular_reference_limit ' ][$ objectHash ]++;
143
+ } else {
144
+ $ context ['circular_reference_limit ' ][$ objectHash ] = 1 ;
145
+ }
146
+
97
147
$ reflectionObject = new \ReflectionObject ($ object );
98
148
$ reflectionMethods = $ reflectionObject ->getMethods (\ReflectionMethod::IS_PUBLIC );
99
149
@@ -114,7 +164,8 @@ public function normalize($object, $format = null, array $context = array())
114
164
if (!$ this ->serializer instanceof NormalizerInterface) {
115
165
throw new \LogicException (sprintf ('Cannot normalize attribute "%s" because injected serializer is not a normalizer ' , $ attributeName ));
116
166
}
117
- $ attributeValue = $ this ->serializer ->normalize ($ attributeValue , $ format );
167
+
168
+ $ attributeValue = $ this ->serializer ->normalize ($ attributeValue , $ format , $ context );
118
169
}
119
170
120
171
$ attributes [$ attributeName ] = $ attributeValue ;
0 commit comments