1<?php
2
3declare(strict_types=1);
4
5namespace JMS\Serializer\Tests\Serializer;
6
7use JMS\Serializer\Context;
8use JMS\Serializer\EventDispatcher\Event;
9use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
10use JMS\Serializer\Exception\RuntimeException;
11use JMS\Serializer\GraphNavigatorInterface;
12use JMS\Serializer\SerializationContext;
13use JMS\Serializer\Tests\Fixtures\Author;
14use JMS\Serializer\Tests\Fixtures\AuthorList;
15use JMS\Serializer\Tests\Fixtures\FirstClassMapCollection;
16use JMS\Serializer\Tests\Fixtures\ObjectWithEmptyArrayAndHash;
17use JMS\Serializer\Tests\Fixtures\ObjectWithInlineArray;
18use JMS\Serializer\Tests\Fixtures\Tag;
19use JMS\Serializer\Visitor\Factory\JsonSerializationVisitorFactory;
20use JMS\Serializer\Visitor\SerializationVisitorInterface;
21
22class JsonSerializationTest extends BaseSerializationTest
23{
24    protected function getContent($key)
25    {
26        static $outputs = [];
27
28        if (!$outputs) {
29            $outputs['readonly'] = '{"id":123,"full_name":"Ruud Kamphuis"}';
30            $outputs['string'] = '"foo"';
31            $outputs['boolean_true'] = 'true';
32            $outputs['boolean_false'] = 'false';
33            $outputs['integer'] = '1';
34            $outputs['float'] = '4.533';
35            $outputs['float_trailing_zero'] = '1.0';
36            $outputs['simple_object'] = '{"foo":"foo","moo":"bar","camel_case":"boo"}';
37            $outputs['circular_reference'] = '{"collection":[{"name":"child1"},{"name":"child2"}],"another_collection":[{"name":"child1"},{"name":"child2"}]}';
38            $outputs['circular_reference_collection'] = '{"name":"foo","collection":[]}';
39            $outputs['array_strings'] = '["foo","bar"]';
40            $outputs['array_booleans'] = '[true,false]';
41            $outputs['array_integers'] = '[1,3,4]';
42            $outputs['array_empty'] = '{"array":[]}';
43            $outputs['array_floats'] = '[1.34,3.0,6.42]';
44            $outputs['array_objects'] = '[{"foo":"foo","moo":"bar","camel_case":"boo"},{"foo":"baz","moo":"boo","camel_case":"boo"}]';
45            $outputs['array_list_and_map_difference'] = '{"list":[1,2,3],"map":{"0":1,"2":2,"3":3}}';
46            $outputs['array_mixed'] = '["foo",1,true,{"foo":"foo","moo":"bar","camel_case":"boo"},[1,3,true]]';
47            $outputs['array_datetimes_object'] = '{"array_with_default_date_time":["2047-01-01T12:47:47+00:00","2016-12-05T00:00:00+00:00"],"array_with_formatted_date_time":["01.01.2047 12:47:47","05.12.2016 00:00:00"]}';
48            $outputs['array_named_datetimes_object'] = '{"named_array_with_formatted_date":{"testdate1":"01.01.2047 12:47:47","testdate2":"05.12.2016 00:00:00"}}';
49            $outputs['array_datetimes_object'] = '{"array_with_default_date_time":["2047-01-01T12:47:47+00:00","2016-12-05T00:00:00+00:00"],"array_with_formatted_date_time":["01.01.2047 12:47:47","05.12.2016 00:00:00"]}';
50            $outputs['array_named_datetimes_object'] = '{"named_array_with_formatted_date":{"testdate1":"01.01.2047 12:47:47","testdate2":"05.12.2016 00:00:00"}}';
51            $outputs['array_named_datetimeimmutables_object'] = '{"named_array_with_formatted_date":{"testdate1":"01.01.2047 12:47:47","testdate2":"05.12.2016 00:00:00"}}';
52            $outputs['blog_post'] = '{"id":"what_a_nice_id","title":"This is a nice title.","created_at":"2011-07-30T00:00:00+00:00","is_published":false,"is_reviewed":false,"etag":"e86ce85cdb1253e4fc6352f5cf297248bceec62b","comments":[{"author":{"full_name":"Foo Bar"},"text":"foo"}],"comments2":[{"author":{"full_name":"Foo Bar"},"text":"foo"}],"metadata":{"foo":"bar"},"author":{"full_name":"Foo Bar"},"publisher":{"pub_name":"Bar Foo"},"tag":[{"name":"tag1"},{"name":"tag2"}]}';
53            $outputs['blog_post_unauthored'] = '{"id":"what_a_nice_id","title":"This is a nice title.","created_at":"2011-07-30T00:00:00+00:00","is_published":false,"is_reviewed":false,"etag":"e86ce85cdb1253e4fc6352f5cf297248bceec62b","comments":[],"comments2":[],"metadata":{"foo":"bar"},"author":null,"publisher":null,"tag":null}';
54            $outputs['price'] = '{"price":3.0}';
55            $outputs['currency_aware_price'] = '{"currency":"EUR","amount":2.34}';
56            $outputs['order'] = '{"cost":{"price":12.34}}';
57            $outputs['order_with_currency_aware_price'] = '{"cost":{"currency":"EUR","amount":1.23}}';
58            $outputs['log'] = '{"author_list":[{"full_name":"Johannes Schmitt"},{"full_name":"John Doe"}],"comments":[{"author":{"full_name":"Foo Bar"},"text":"foo"},{"author":{"full_name":"Foo Bar"},"text":"bar"},{"author":{"full_name":"Foo Bar"},"text":"baz"}]}';
59            $outputs['lifecycle_callbacks'] = '{"name":"Foo Bar"}';
60            $outputs['form_errors'] = '["This is the form error","Another error"]';
61            $outputs['nested_form_errors'] = '{"errors":["This is the form error"],"children":{"bar":{"errors":["Error of the child form"]}}}';
62            $outputs['constraint_violation'] = '{"property_path":"foo","message":"Message of violation"}';
63            $outputs['constraint_violation_list'] = '[{"property_path":"foo","message":"Message of violation"},{"property_path":"bar","message":"Message of another violation"}]';
64            $outputs['article'] = '{"custom":"serialized"}';
65            $outputs['orm_proxy'] = '{"foo":"foo","moo":"bar","camel_case":"proxy-boo"}';
66            $outputs['custom_accessor'] = '{"comments":{"Foo":{"comments":[{"author":{"full_name":"Foo"},"text":"foo"},{"author":{"full_name":"Foo"},"text":"bar"}],"count":2}}}';
67            $outputs['mixed_access_types'] = '{"id":1,"name":"Johannes","read_only_property":42}';
68            $outputs['accessor_order_child'] = '{"c":"c","d":"d","a":"a","b":"b"}';
69            $outputs['accessor_order_parent'] = '{"a":"a","b":"b"}';
70            $outputs['accessor_order_methods'] = '{"foo":"c","b":"b","a":"a"}';
71            $outputs['inline'] = '{"c":"c","a":"a","b":"b","d":"d"}';
72            $outputs['inline_child_empty'] = '{"c":"c","d":"d"}';
73            $outputs['empty_child'] = '{"c":"c","d":"d","child":{}}';
74            $outputs['empty_child_skip'] = '{"c":"c","d":"d"}';
75            $outputs['groups_all'] = '{"foo":"foo","foobar":"foobar","bar":"bar","none":"none"}';
76            $outputs['groups_foo'] = '{"foo":"foo","foobar":"foobar"}';
77            $outputs['groups_foobar'] = '{"foo":"foo","foobar":"foobar","bar":"bar"}';
78            $outputs['groups_default'] = '{"bar":"bar","none":"none"}';
79            $outputs['groups_advanced'] = '{"name":"John","manager":{"name":"John Manager","friends":[{"nickname":"nickname"},{"nickname":"nickname"}]},"friends":[{"nickname":"nickname","manager":{"nickname":"nickname"}},{"nickname":"nickname","manager":{"nickname":"nickname"}}]}';
80            $outputs['virtual_properties'] = '{"exist_field":"value","virtual_value":"value","test":"other-name","typed_virtual_property":1}';
81            $outputs['virtual_properties_low'] = '{"classlow":1,"low":1}';
82            $outputs['virtual_properties_high'] = '{"classhigh":8,"high":8}';
83            $outputs['virtual_properties_all'] = '{"classlow":1,"classhigh":8,"low":1,"high":8}';
84            $outputs['nullable'] = '{"foo":"bar","baz":null,"0":null}';
85            $outputs['nullable_skip'] = '{"foo":"bar"}';
86            $outputs['person_secret_show'] = '{"name":"mike","gender":"f"}';
87            $outputs['person_secret_hide'] = '{"name":"mike"}';
88            $outputs['null'] = 'null';
89            $outputs['simple_object_nullable'] = '{"foo":"foo","moo":"bar","camel_case":"boo","null_property":null}';
90            $outputs['input'] = '{"attributes":{"type":"text","name":"firstname","value":"Adrien"}}';
91            $outputs['hash_empty'] = '{"hash":{}}';
92            $outputs['object_when_null'] = '{"text":"foo"}';
93            $outputs['object_when_null_and_serialized'] = '{"author":null,"text":"foo"}';
94            $outputs['date_time'] = '"2011-08-30T00:00:00+00:00"';
95            $outputs['date_time_immutable'] = '"2011-08-30T00:00:00+00:00"';
96            $outputs['timestamp'] = '{"timestamp":1455148800}';
97            $outputs['timestamp_prev'] = '{"timestamp":"1455148800"}';
98            $outputs['date_interval'] = '"PT45M"';
99            $outputs['car'] = '{"km":5,"type":"car"}';
100            $outputs['car_without_type'] = '{"km":5}';
101            $outputs['post'] = '{"type":"post","title":"Post Title"}';
102            $outputs['image_post'] = '{"type":"image_post","title":"Image Post Title"}';
103            $outputs['image_post_without_type'] = '{"title":"Image Post Title"}';
104            $outputs['garage'] = '{"vehicles":[{"km":3,"type":"car"},{"km":1,"type":"moped"}]}';
105            $outputs['tree'] = '{"tree":{"children":[{"children":[{"children":[],"foo":"bar"}],"foo":"bar"}],"foo":"bar"}}';
106            $outputs['nullable_arrays'] = '{"empty_inline":[],"not_empty_inline":["not_empty_inline"],"empty_not_inline":[],"not_empty_not_inline":["not_empty_not_inline"],"empty_not_inline_skip":[],"not_empty_not_inline_skip":["not_empty_not_inline_skip"]}';
107            $outputs['object_with_object_property_no_array_to_author'] = '{"foo": "bar", "author": "baz"}';
108            $outputs['object_with_object_property'] = '{"foo": "bar", "author": {"full_name": "baz"}}';
109            $outputs['author_expression'] = '{"my_first_name":"Ruud","last_name":"Kamphuis","id":123}';
110            $outputs['author_expression_context'] = '{"first_name":"Ruud","direction":1,"name":"name"}';
111            $outputs['maxdepth_skippabe_object'] = '{"a":{"xxx":"yyy"}}';
112            $outputs['array_objects_nullable'] = '[]';
113            $outputs['type_casting'] = '{"as_string":"8"}';
114            $outputs['authors_inline'] = '[{"full_name":"foo"},{"full_name":"bar"}]';
115            $outputs['inline_list_collection'] = '[1,2,3]';
116            $outputs['inline_empty_list_collection'] = '[]';
117            $outputs['inline_deserialization_list_collection'] = '[1,2]';
118            $outputs['inline_map'] = '{"0":"1","1":"2","2":"3"}';
119            $outputs['inline_empty_map'] = '{}';
120            $outputs['empty_object'] = '{}';
121            $outputs['inline_deserialization_map'] = '{"a":"b","c":"d","0":"5"}';
122            $outputs['iterator'] = '{"iterator":{"foo":"bar","bar":"foo"}}';
123            $outputs['generator'] = '{"generator":{"foo":"bar","bar":"foo"}}';
124        }
125
126        if (!isset($outputs[$key])) {
127            throw new RuntimeException(sprintf('The key "%s" is not supported.', $key));
128        }
129
130        return $outputs[$key];
131    }
132
133    public function testSkipEmptyArrayAndHash()
134    {
135        $object = new ObjectWithEmptyArrayAndHash();
136
137        self::assertEquals('{}', $this->serialize($object));
138    }
139
140    public function getFirstClassMapCollectionsValues()
141    {
142        return [
143            [[1, 2, 3], $this->getContent('inline_map')],
144            [[], $this->getContent('inline_empty_map')],
145            [['a' => 'b', 'c' => 'd', 5], $this->getContent('inline_deserialization_map')],
146        ];
147    }
148
149    /**
150     * @param array $items
151     * @param array $expected
152     *
153     * @dataProvider getFirstClassMapCollectionsValues
154     */
155    public function testFirstClassMapCollections($items, $expected): void
156    {
157        $collection = new FirstClassMapCollection($items);
158
159        self::assertSame($expected, $this->serialize($collection));
160        self::assertEquals(
161            $collection,
162            $this->deserialize($expected, get_class($collection))
163        );
164    }
165
166    public function testAddLinksToOutput()
167    {
168        $this->dispatcher->addListener('serializer.post_serialize', static function (Event $event) {
169            self::assertFalse($event->getVisitor()->hasData('_links'));
170        }, 'JMS\Serializer\Tests\Fixtures\Author', 'json');
171
172        $this->dispatcher->addSubscriber(new LinkAddingSubscriber());
173
174        $this->dispatcher->addListener('serializer.post_serialize', static function (Event $event) {
175            self::assertTrue($event->getVisitor()->hasData('_links'));
176        }, 'JMS\Serializer\Tests\Fixtures\Author', 'json');
177
178        $this->handlerRegistry->registerHandler(
179            GraphNavigatorInterface::DIRECTION_SERIALIZATION,
180            'JMS\Serializer\Tests\Fixtures\AuthorList',
181            'json',
182            static function (SerializationVisitorInterface $visitor, AuthorList $data, array $type, Context $context) {
183                return $visitor->visitArray(iterator_to_array($data), $type);
184            }
185        );
186
187        $list = new AuthorList();
188        $list->add(new Author('foo'));
189        $list->add(new Author('bar'));
190
191        self::assertEquals('[{"full_name":"foo","_links":{"details":"http:\/\/foo.bar\/details\/foo","comments":"http:\/\/foo.bar\/details\/foo\/comments"}},{"full_name":"bar","_links":{"details":"http:\/\/foo.bar\/details\/bar","comments":"http:\/\/foo.bar\/details\/bar\/comments"}}]', $this->serialize($list));
192    }
193
194    public function testReplaceNameInOutput()
195    {
196        $this->dispatcher->addSubscriber(new ReplaceNameSubscriber());
197        $this->handlerRegistry->registerHandler(
198            GraphNavigatorInterface::DIRECTION_SERIALIZATION,
199            'JMS\Serializer\Tests\Fixtures\AuthorList',
200            'json',
201            static function (SerializationVisitorInterface $visitor, AuthorList $data, array $type, Context $context) {
202                return $visitor->visitArray(iterator_to_array($data), $type);
203            }
204        );
205
206        $list = new AuthorList();
207        $list->add(new Author('foo'));
208        $list->add(new Author('bar'));
209
210        self::assertEquals('[{"full_name":"new name"},{"full_name":"new name"}]', $this->serialize($list));
211    }
212
213    /**
214     * @expectedException RuntimeException
215     * @expectedExceptionMessage Invalid data "baz" (string), expected "JMS\Serializer\Tests\Fixtures\Author".
216     */
217    public function testDeserializingObjectWithObjectPropertyWithNoArrayToObject()
218    {
219        $content = $this->getContent('object_with_object_property_no_array_to_author');
220        $object = $this->deserialize($content, 'JMS\Serializer\Tests\Fixtures\ObjectWithObjectProperty');
221        self::assertEquals('bar', $object->getFoo());
222        self::assertInstanceOf('JMS\Serializer\Tests\Fixtures\Author', $object->getAuthor());
223    }
224
225    public function testDeserializingObjectWithObjectProperty()
226    {
227        $content = $this->getContent('object_with_object_property');
228        $object = $this->deserialize($content, 'JMS\Serializer\Tests\Fixtures\ObjectWithObjectProperty');
229        self::assertEquals('bar', $object->getFoo());
230        self::assertInstanceOf('JMS\Serializer\Tests\Fixtures\Author', $object->getAuthor());
231        self::assertEquals('baz', $object->getAuthor()->getName());
232    }
233
234    public function getPrimitiveTypes()
235    {
236        return [
237            [
238                'type' => 'boolean',
239                'data' => true,
240            ],
241            [
242                'type' => 'integer',
243                'data' => 123,
244            ],
245            [
246                'type' => 'string',
247                'data' => 'hello',
248            ],
249            [
250                'type' => 'double',
251                'data' => 0.1234,
252            ],
253        ];
254    }
255
256    /**
257     * @dataProvider getPrimitiveTypes
258     */
259    public function testPrimitiveTypes($primitiveType, $data)
260    {
261        $navigator = $this->getMockBuilder(GraphNavigatorInterface::class)->getMock();
262
263        $factory = new JsonSerializationVisitorFactory();
264        $visitor = $factory->getVisitor();
265        $visitor->setNavigator($navigator);
266        $functionToCall = 'visit' . ucfirst($primitiveType);
267        $result = $visitor->$functionToCall($data, [], $this->getMockBuilder(SerializationContext::class)->getMock());
268        if ('double' === $primitiveType) {
269            $primitiveType = 'float';
270        }
271        self::assertInternalType($primitiveType, $result);
272    }
273
274    /**
275     * @group empty-object
276     */
277    public function testSerializeEmptyObject()
278    {
279        self::assertEquals('{}', $this->serialize(new Author(null)));
280    }
281
282    /**
283     * @group encoding
284     * @expectedException RuntimeException
285     * @expectedExceptionMessage Your data could not be encoded because it contains invalid UTF8 characters.
286     */
287    public function testSerializeWithNonUtf8EncodingWhenDisplayErrorsOff()
288    {
289        ini_set('display_errors', '1');
290        $this->serialize(['foo' => 'bar', 'bar' => pack('H*', 'c32e')]);
291    }
292
293    /**
294     * @group encoding
295     * @expectedException RuntimeException
296     * @expectedExceptionMessage Your data could not be encoded because it contains invalid UTF8 characters.
297     */
298    public function testSerializeWithNonUtf8EncodingWhenDisplayErrorsOn()
299    {
300        ini_set('display_errors', '0');
301        $this->serialize(['foo' => 'bar', 'bar' => pack('H*', 'c32e')]);
302    }
303
304    public function testSerializeArrayWithEmptyObject()
305    {
306        self::assertEquals('[{}]', $this->serialize([new \stdClass()]));
307    }
308
309    public function testInlineArray()
310    {
311        $object = new ObjectWithInlineArray(['a' => 'b', 'c' => 'd']);
312        $serialized = $this->serialize($object);
313        self::assertEquals('{"a":"b","c":"d"}', $serialized);
314        self::assertEquals($object, $this->deserialize($serialized, ObjectWithInlineArray::class));
315    }
316
317    public function testSerializeRootArrayWithDefinedKeys()
318    {
319        $author1 = new Author('Jim');
320        $author2 = new Author('Mark');
321
322        $data = [
323            'jim' => $author1,
324            'mark' => $author2,
325        ];
326
327        self::assertEquals('{"jim":{"full_name":"Jim"},"mark":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array')));
328        self::assertEquals('[{"full_name":"Jim"},{"full_name":"Mark"}]', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<JMS\Serializer\Tests\Fixtures\Author>')));
329        self::assertEquals('{"jim":{"full_name":"Jim"},"mark":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<string,JMS\Serializer\Tests\Fixtures\Author>')));
330
331        $data = [
332            $author1,
333            $author2,
334        ];
335        self::assertEquals('[{"full_name":"Jim"},{"full_name":"Mark"}]', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array')));
336        self::assertEquals('{"0":{"full_name":"Jim"},"1":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<int,JMS\Serializer\Tests\Fixtures\Author>')));
337        self::assertEquals('{"0":{"full_name":"Jim"},"1":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<string,JMS\Serializer\Tests\Fixtures\Author>')));
338    }
339
340    public function getTypeHintedArrays()
341    {
342        return [
343
344            [[1, 2], '[1,2]', null],
345            [['a', 'b'], '["a","b"]', null],
346            [['a' => 'a', 'b' => 'b'], '{"a":"a","b":"b"}', null],
347
348            [[], '[]', null],
349            [[], '[]', SerializationContext::create()->setInitialType('array')],
350            [[], '[]', SerializationContext::create()->setInitialType('array<integer>')],
351            [[], '{}', SerializationContext::create()->setInitialType('array<string,integer>')],
352
353            [[1, 2], '[1,2]', SerializationContext::create()->setInitialType('array')],
354            [[1 => 1, 2 => 2], '{"1":1,"2":2}', SerializationContext::create()->setInitialType('array')],
355            [[1 => 1, 2 => 2], '[1,2]', SerializationContext::create()->setInitialType('array<integer>')],
356            [['a', 'b'], '["a","b"]', SerializationContext::create()->setInitialType('array<string>')],
357
358            [[1 => 'a', 2 => 'b'], '["a","b"]', SerializationContext::create()->setInitialType('array<string>')],
359            [['a' => 'a', 'b' => 'b'], '["a","b"]', SerializationContext::create()->setInitialType('array<string>')],
360
361            [[1, 2], '{"0":1,"1":2}', SerializationContext::create()->setInitialType('array<integer,integer>')],
362            [[1, 2], '{"0":1,"1":2}', SerializationContext::create()->setInitialType('array<string,integer>')],
363            [[1, 2], '{"0":"1","1":"2"}', SerializationContext::create()->setInitialType('array<string,string>')],
364
365            [['a', 'b'], '{"0":"a","1":"b"}', SerializationContext::create()->setInitialType('array<integer,string>')],
366            [['a' => 'a', 'b' => 'b'], '{"a":"a","b":"b"}', SerializationContext::create()->setInitialType('array<string,string>')],
367        ];
368    }
369
370    /**
371     * @param array $array
372     * @param string $expected
373     * @param SerializationContext|null $context
374     *
375     * @dataProvider getTypeHintedArrays
376     */
377    public function testTypeHintedArraySerialization(array $array, $expected, $context = null)
378    {
379        self::assertEquals($expected, $this->serialize($array, $context));
380    }
381
382    public function getTypeHintedArraysAndStdClass()
383    {
384        $c1 = new \stdClass();
385        $c2 = new \stdClass();
386        $c2->foo = 'bar';
387
388        $tag = new Tag('tag');
389
390        $c3 = new \stdClass();
391        $c3->foo = $tag;
392
393        return [
394
395            [[$c1], '[{}]', SerializationContext::create()->setInitialType('array<stdClass>')],
396
397            [[$c2], '[{"foo":"bar"}]', SerializationContext::create()->setInitialType('array<stdClass>')],
398
399            [[$tag], '[{"name":"tag"}]', SerializationContext::create()->setInitialType('array<JMS\Serializer\Tests\Fixtures\Tag>')],
400
401            [[$c1], '{"0":{}}', SerializationContext::create()->setInitialType('array<integer,stdClass>')],
402            [[$c2], '{"0":{"foo":"bar"}}', SerializationContext::create()->setInitialType('array<integer,stdClass>')],
403
404            [[$c3], '{"0":{"foo":{"name":"tag"}}}', SerializationContext::create()->setInitialType('array<integer,stdClass>')],
405            [[$c3], '[{"foo":{"name":"tag"}}]', SerializationContext::create()->setInitialType('array<stdClass>')],
406
407            [[$tag], '{"0":{"name":"tag"}}', SerializationContext::create()->setInitialType('array<integer,JMS\Serializer\Tests\Fixtures\Tag>')],
408        ];
409    }
410
411    /**
412     * @param array $array
413     * @param string $expected
414     * @param SerializationContext|null $context
415     *
416     * @dataProvider getTypeHintedArraysAndStdClass
417     */
418    public function testTypeHintedArrayAndStdClassSerialization(array $array, $expected, $context = null)
419    {
420        self::assertEquals($expected, $this->serialize($array, $context));
421    }
422
423    protected function getFormat()
424    {
425        return 'json';
426    }
427}
428
429class LinkAddingSubscriber implements EventSubscriberInterface
430{
431    public function onPostSerialize(Event $event)
432    {
433        $author = $event->getObject();
434
435        $event->getVisitor()->setData('_links', [
436            'details' => 'http://foo.bar/details/' . $author->getName(),
437            'comments' => 'http://foo.bar/details/' . $author->getName() . '/comments',
438        ]);
439    }
440
441    public static function getSubscribedEvents()
442    {
443        return [
444            ['event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => 'JMS\Serializer\Tests\Fixtures\Author'],
445        ];
446    }
447}
448
449class ReplaceNameSubscriber implements EventSubscriberInterface
450{
451    public function onPostSerialize(Event $event)
452    {
453        $event->getVisitor()->setData('full_name', 'new name');
454    }
455
456    public static function getSubscribedEvents()
457    {
458        return [
459            ['event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => 'JMS\Serializer\Tests\Fixtures\Author'],
460        ];
461    }
462}
463