1<?php
2
3namespace JMS\SerializerBundle\Tests\DependencyInjection;
4
5use JMS\Serializer\Exception\RuntimeException;
6use JMS\SerializerBundle\DependencyInjection\Compiler\CustomHandlersPass;
7use JMS\SerializerBundle\DependencyInjection\JMSSerializerExtension;
8use PHPUnit\Framework\TestCase;
9use Symfony\Component\DependencyInjection\ContainerBuilder;
10use Symfony\Component\DependencyInjection\Definition;
11use Symfony\Component\DependencyInjection\Reference;
12
13class CustomHandlerPassTest extends TestCase
14{
15    /**
16     * @param array $configs
17     * @return ContainerBuilder
18     */
19    private function getContainer(array $configs = array())
20    {
21        $loader = new JMSSerializerExtension();
22        $container = new ContainerBuilder();
23
24        $container->setParameter('kernel.debug', true);
25        $container->setParameter('kernel.cache_dir', sys_get_temp_dir() . '/serializer');
26        $container->setParameter('kernel.bundles', array());
27        $container->setParameter('kernel.bundles', array());
28
29        $loader->load(['jms_serializer' => $configs], $container);
30
31        // remove other subscribers
32        foreach (array_keys($container->findTaggedServiceIds('jms_serializer.handler')) as $id) {
33            $container->removeDefinition($id);
34        }
35        foreach (array_keys($container->findTaggedServiceIds('jms_serializer.subscribing_handler')) as $id) {
36            $container->removeDefinition($id);
37        }
38
39        return $container;
40    }
41
42    public function testHandler()
43    {
44        $container = $this->getContainer();
45
46        $def = new Definition('Foo');
47        $def->addTag('jms_serializer.handler', [
48            'type' => 'DateTime',
49            'format' => 'json',
50        ]);
51        $container->setDefinition('my_service', $def);
52
53        $pass = new CustomHandlersPass();
54        $pass->process($container);
55
56        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
57
58        $this->assertSame([
59            2 => ['DateTime' => ['json' => ['my_service', 'deserializeDateTimeFromjson']]],
60            1 => ['DateTime' => ['json' => ['my_service', 'serializeDateTimeTojson']]]
61        ], $args[1]);
62    }
63
64    public function testHandlerCanBePrivate()
65    {
66        $container = $this->getContainer();
67
68        $def = new Definition('Foo');
69        $def->setPublic(false);
70        $def->addTag('jms_serializer.handler', [
71            'type' => 'DateTime',
72            'format' => 'json',
73        ]);
74        $container->setDefinition('my_service', $def);
75
76        $pass = new CustomHandlersPass();
77        $pass->process($container);
78
79        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
80
81        $this->assertEquals([
82            2 => ['DateTime' => ['json' => [new Reference('my_service'), 'deserializeDateTimeFromjson']]],
83            1 => ['DateTime' => ['json' => [new Reference('my_service'), 'serializeDateTimeTojson']]]
84        ], $args[1]);
85    }
86
87    public function testHandlerDirection()
88    {
89        $container = $this->getContainer();
90
91        $def = new Definition('Foo');
92        $def->addTag('jms_serializer.handler', [
93            'type' => 'DateTime',
94            'format' => 'json',
95            'direction' => 'SERIALIZATION',
96        ]);
97        $container->setDefinition('my_service', $def);
98
99        $pass = new CustomHandlersPass();
100        $pass->process($container);
101
102        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
103
104        $this->assertSame([
105            1 => ['DateTime' => ['json' => ['my_service', 'serializeDateTimeTojson']]]
106        ], $args[1]);
107    }
108
109    /**
110     * @expectedException RuntimeException
111     * @expectedExceptionMessage The direction "bar" of tag "jms_serializer.handler" of service "my_service" does not exist
112     */
113    public function testHandlerIncorrectDirection()
114    {
115        $container = $this->getContainer();
116
117        $def = new Definition('Foo');
118        $def->addTag('jms_serializer.handler', [
119            'type' => 'DateTime',
120            'format' => 'json',
121            'direction' => 'bar',
122        ]);
123        $container->setDefinition('my_service', $def);
124
125        $pass = new CustomHandlersPass();
126        $pass->process($container);
127    }
128
129    /**
130     * @expectedException RuntimeException
131     * @expectedExceptionMessage Each tag named "jms_serializer.handler" of service "my_service" must have at least two attributes: "type" and "format"
132     */
133    public function testHandlerMustHaveTypeAndFormat()
134    {
135        $container = $this->getContainer();
136
137        $def = new Definition('Foo');
138        $def->addTag('jms_serializer.handler');
139        $container->setDefinition('my_service', $def);
140
141        $pass = new CustomHandlersPass();
142        $pass->process($container);
143    }
144
145    public function testHandlerMustPrioritizeUserDefined()
146    {
147        $container = $this->getContainer();
148
149        $def = new Definition('JMS\Serializer\Foo');
150        $def->addTag('jms_serializer.handler', [
151            'type' => 'DateTime',
152            'format' => 'json',
153        ]);
154        $container->setDefinition('my_service', $def);
155
156        $userDef = new Definition('Bar');
157        $userDef->addTag('jms_serializer.handler', [
158            'type' => 'DateTime',
159            'format' => 'json',
160        ]);
161        $container->setDefinition('my_custom_service', $userDef);
162
163        $pass = new CustomHandlersPass();
164        $pass->process($container);
165
166        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
167
168        $this->assertSame([
169            2 => ['DateTime' => ['json' => ['my_custom_service', 'deserializeDateTimeFromjson']]],
170            1 => ['DateTime' => ['json' => ['my_custom_service', 'serializeDateTimeTojson']]]
171        ], $args[1]);
172    }
173
174    public function testHandlerMustRespectPriorities()
175    {
176        $container = $this->getContainer();
177
178        $def = new Definition('JMS\Serializer\Foo');
179        $def->addTag('jms_serializer.handler', [
180            'type' => 'DateTime',
181            'format' => 'json',
182        ]);
183        $container->setDefinition('my_service', $def);
184
185        $userDef = new Definition('Bar');
186        $userDef->addTag('jms_serializer.handler', [
187            'type' => 'DateTime',
188            'format' => 'json',
189        ]);
190        $container->setDefinition('my_custom_service', $userDef);
191
192        $userExplicitDef = new Definition('Baz');
193        $userExplicitDef->addTag('jms_serializer.handler', [
194            'type' => 'DateTime',
195            'format' => 'json',
196            'priority' => -100
197        ]);
198        $container->setDefinition('my_custom_explicit_service', $userExplicitDef);
199
200        $pass = new CustomHandlersPass();
201        $pass->process($container);
202
203        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
204
205        $this->assertSame([
206          2 => ['DateTime' => ['json' => ['my_custom_explicit_service', 'deserializeDateTimeFromjson']]],
207          1 => ['DateTime' => ['json' => ['my_custom_explicit_service', 'serializeDateTimeTojson']]]
208        ], $args[1]);
209    }
210
211    public function testHandlerCanBeRegisteredForMultipleTypesOrDirections()
212    {
213        $container = $this->getContainer();
214
215        $def = new Definition('JMS\Serializer\Foo');
216        $def->addTag('jms_serializer.handler', [
217            'type' => 'Custom',
218            'direction' => 'serialization',
219            'format' => 'json',
220            'method' => 'serialize',
221        ]);
222        $def->addTag('jms_serializer.handler', [
223            'type' => 'Custom',
224            'direction' => 'deserialization',
225            'format' => 'json',
226            'method' => 'deserialize',
227        ]);
228        $def->addTag('jms_serializer.handler', [
229            'type' => 'Custom<?>',
230            'direction' => 'serialization',
231            'format' => 'json',
232            'method' => 'serialize',
233        ]);
234        $def->addTag('jms_serializer.handler', [
235            'type' => 'Custom<?>',
236            'direction' => 'deserialization',
237            'format' => 'json',
238            'method' => 'deserialize',
239        ]);
240        $container->setDefinition('my_service', $def);
241
242        $pass = new CustomHandlersPass();
243        $pass->process($container);
244
245        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
246
247        $this->assertSame([
248            1 => [
249                'Custom' => ['json' => ['my_service', 'serialize']],
250                'Custom<?>' => ['json' => ['my_service', 'serialize']],
251            ],
252            2 => [
253                'Custom' => ['json' => ['my_service', 'deserialize']],
254                'Custom<?>' => ['json' => ['my_service', 'deserialize']],
255            ]
256        ], $args[1]);
257    }
258
259    public function testSubscribingHandler()
260    {
261        $container = $this->getContainer();
262
263        $def = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\SubscribingHandler');
264        $def->addTag('jms_serializer.subscribing_handler');
265        $container->setDefinition('my_service', $def);
266
267        $pass = new CustomHandlersPass();
268        $pass->process($container);
269
270        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
271
272        $this->assertSame([
273            1 => ['DateTime' => ['json' => ['my_service', 'onDateTime']]]
274        ], $args[1]);
275    }
276
277    public function testSubscribingHandlerCanBePrivate()
278    {
279        $container = $this->getContainer();
280
281        $def = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\SubscribingHandler');
282        $def->addTag('jms_serializer.subscribing_handler');
283        $def->setPublic(false);
284        $container->setDefinition('my_service', $def);
285
286        $pass = new CustomHandlersPass();
287        $pass->process($container);
288
289        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
290
291        $this->assertEquals([
292            1 => ['DateTime' => ['json' => [new Reference('my_service'), 'onDateTime']]]
293        ], $args[1]);
294    }
295
296    /**
297     * @expectedException RuntimeException
298     * @expectedExceptionMessage The service "my_service" must implement the SubscribingHandlerInterface
299     */
300    public function testSubscribingHandlerInterface()
301    {
302        $container = $this->getContainer();
303
304        $def = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\SimpleObject');
305        $def->addTag('jms_serializer.subscribing_handler');
306        $container->setDefinition('my_service', $def);
307
308        $pass = new CustomHandlersPass();
309        $pass->process($container);
310    }
311
312    public function testSubscribingHandlerMustPrioritizeUserDefined()
313    {
314        $container = $this->getContainer();
315
316        $def = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\SubscribingHandler');
317        $def->addTag('jms_serializer.subscribing_handler');
318        $container->setDefinition('my_service', $def);
319
320        $userDef = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\UserDefined\UserDefinedSubscribingHandler');
321        $userDef->addTag('jms_serializer.subscribing_handler');
322        $container->setDefinition('my_custom_service', $userDef);
323
324        $pass = new CustomHandlersPass();
325        $pass->process($container);
326
327        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
328
329        $this->assertSame([
330            1 => ['DateTime' => ['json' => ['my_custom_service', 'onDateTime']]]
331        ], $args[1]);
332    }
333
334    public function testSubscribingHandlerMustRespectPriorities()
335    {
336        $container = $this->getContainer();
337
338        $def = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\SubscribingHandler');
339        $def->addTag('jms_serializer.subscribing_handler');
340        $container->setDefinition('my_service', $def);
341
342        $userDef = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\UserDefined\UserDefinedSubscribingHandler');
343        $userDef->addTag('jms_serializer.subscribing_handler');
344        $container->setDefinition('my_custom_service', $userDef);
345
346        $userExplicitDef = new Definition('JMS\SerializerBundle\Tests\DependencyInjection\Fixture\UserDefined\UserDefinedSubscribingHandler');
347        $userExplicitDef->addTag('jms_serializer.subscribing_handler', ['priority' => -100]);
348        $container->setDefinition('my_custom_explicit_service', $userExplicitDef);
349
350        $pass = new CustomHandlersPass();
351        $pass->process($container);
352
353        $args = $container->getDefinition('jms_serializer.handler_registry')->getArguments();
354
355        $this->assertSame([
356            1 => ['DateTime' => ['json' => ['my_custom_explicit_service', 'onDateTime']]]
357        ], $args[1]);
358    }
359
360}
361