4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Serializer\Tests\Normalizer;
14 use Doctrine\Common\Annotations\AnnotationReader;
15 use PHPUnit\Framework\TestCase;
16 use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
17 use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
18 use Symfony\Component\Serializer\Serializer;
19 use Symfony\Component\Serializer\SerializerInterface;
20 use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
21 use Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy;
22 use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder;
23 use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
24 use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
25 use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
27 class GetSetMethodNormalizerTest extends TestCase
30 * @var GetSetMethodNormalizer
34 * @var SerializerInterface
38 protected function setUp()
40 $this->serializer = $this->getMockBuilder(__NAMESPACE__.'\SerializerNormalizer')->getMock();
41 $this->normalizer = new GetSetMethodNormalizer();
42 $this->normalizer->setSerializer($this->serializer);
45 public function testInterface()
47 $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $this->normalizer);
48 $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $this->normalizer);
51 public function testNormalize()
53 $obj = new GetSetDummy();
54 $object = new \stdClass();
58 $obj->setCamelCase('camelcase');
59 $obj->setObject($object);
62 ->expects($this->once())
64 ->with($object, 'any')
65 ->will($this->returnValue('string_object'))
74 'camelCase' => 'camelcase',
75 'object' => 'string_object',
77 $this->normalizer->normalize($obj, 'any')
81 public function testDenormalize()
83 $obj = $this->normalizer->denormalize(
84 array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'),
85 __NAMESPACE__.'\GetSetDummy',
88 $this->assertEquals('foo', $obj->getFoo());
89 $this->assertEquals('bar', $obj->getBar());
90 $this->assertTrue($obj->isBaz());
93 public function testDenormalizeWithObject()
95 $data = new \stdClass();
98 $data->fooBar = 'foobar';
99 $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetSetDummy', 'any');
100 $this->assertEquals('foo', $obj->getFoo());
101 $this->assertEquals('bar', $obj->getBar());
107 public function testLegacyDenormalizeOnCamelCaseFormat()
109 $this->normalizer->setCamelizedAttributes(array('camel_case'));
110 $obj = $this->normalizer->denormalize(
111 array('camel_case' => 'camelCase'),
112 __NAMESPACE__.'\GetSetDummy'
115 $this->assertEquals('camelCase', $obj->getCamelCase());
118 public function testNameConverterSupport()
120 $this->normalizer = new GetSetMethodNormalizer(null, new CamelCaseToSnakeCaseNameConverter());
121 $obj = $this->normalizer->denormalize(
122 array('camel_case' => 'camelCase'),
123 __NAMESPACE__.'\GetSetDummy'
125 $this->assertEquals('camelCase', $obj->getCamelCase());
128 public function testDenormalizeNull()
130 $this->assertEquals(new GetSetDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\GetSetDummy'));
136 public function testLegacyCamelizedAttributesNormalize()
138 $obj = new GetCamelizedDummy('dunglas.fr');
139 $obj->setFooBar('les-tilleuls.coop');
140 $obj->setBar_foo('lostinthesupermarket.fr');
142 $this->normalizer->setCamelizedAttributes(array('kevin_dunglas'));
143 $this->assertEquals($this->normalizer->normalize($obj), array(
144 'kevin_dunglas' => 'dunglas.fr',
145 'fooBar' => 'les-tilleuls.coop',
146 'bar_foo' => 'lostinthesupermarket.fr',
149 $this->normalizer->setCamelizedAttributes(array('foo_bar'));
150 $this->assertEquals($this->normalizer->normalize($obj), array(
151 'kevinDunglas' => 'dunglas.fr',
152 'foo_bar' => 'les-tilleuls.coop',
153 'bar_foo' => 'lostinthesupermarket.fr',
160 public function testLegacyCamelizedAttributesDenormalize()
162 $obj = new GetCamelizedDummy('dunglas.fr');
163 $obj->setFooBar('les-tilleuls.coop');
164 $obj->setBar_foo('lostinthesupermarket.fr');
166 $this->normalizer->setCamelizedAttributes(array('kevin_dunglas'));
167 $this->assertEquals($this->normalizer->denormalize(array(
168 'kevin_dunglas' => 'dunglas.fr',
169 'fooBar' => 'les-tilleuls.coop',
170 'bar_foo' => 'lostinthesupermarket.fr',
171 ), __NAMESPACE__.'\GetCamelizedDummy'), $obj);
173 $this->normalizer->setCamelizedAttributes(array('foo_bar'));
174 $this->assertEquals($this->normalizer->denormalize(array(
175 'kevinDunglas' => 'dunglas.fr',
176 'foo_bar' => 'les-tilleuls.coop',
177 'bar_foo' => 'lostinthesupermarket.fr',
178 ), __NAMESPACE__.'\GetCamelizedDummy'), $obj);
181 public function testConstructorDenormalize()
183 $obj = $this->normalizer->denormalize(
184 array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'),
185 __NAMESPACE__.'\GetConstructorDummy', 'any');
186 $this->assertEquals('foo', $obj->getFoo());
187 $this->assertEquals('bar', $obj->getBar());
188 $this->assertTrue($obj->isBaz());
191 public function testConstructorDenormalizeWithNullArgument()
193 $obj = $this->normalizer->denormalize(
194 array('foo' => 'foo', 'bar' => null, 'baz' => true),
195 __NAMESPACE__.'\GetConstructorDummy', 'any');
196 $this->assertEquals('foo', $obj->getFoo());
197 $this->assertNull($obj->getBar());
198 $this->assertTrue($obj->isBaz());
201 public function testConstructorDenormalizeWithMissingOptionalArgument()
203 $obj = $this->normalizer->denormalize(
204 array('foo' => 'test', 'baz' => array(1, 2, 3)),
205 __NAMESPACE__.'\GetConstructorOptionalArgsDummy', 'any');
206 $this->assertEquals('test', $obj->getFoo());
207 $this->assertEquals(array(), $obj->getBar());
208 $this->assertEquals(array(1, 2, 3), $obj->getBaz());
212 * @see https://bugs.php.net/62715
214 * @requires PHP 5.3.17
216 public function testConstructorDenormalizeWithOptionalDefaultArgument()
218 $obj = $this->normalizer->denormalize(
219 array('bar' => 'test'),
220 __NAMESPACE__.'\GetConstructorArgsWithDefaultValueDummy', 'any');
221 $this->assertEquals(array(), $obj->getFoo());
222 $this->assertEquals('test', $obj->getBar());
228 public function testConstructorDenormalizeWithVariadicArgument()
230 $obj = $this->normalizer->denormalize(
231 array('foo' => array(1, 2, 3)),
232 'Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorArgsDummy', 'any');
233 $this->assertEquals(array(1, 2, 3), $obj->getFoo());
239 public function testConstructorDenormalizeWithMissingVariadicArgument()
241 $obj = $this->normalizer->denormalize(
243 'Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorArgsDummy', 'any');
244 $this->assertEquals(array(), $obj->getFoo());
247 public function testConstructorWithObjectDenormalize()
249 $data = new \stdClass();
253 $data->fooBar = 'foobar';
254 $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetConstructorDummy', 'any');
255 $this->assertEquals('foo', $obj->getFoo());
256 $this->assertEquals('bar', $obj->getBar());
259 public function testConstructorWArgWithPrivateMutator()
261 $obj = $this->normalizer->denormalize(array('foo' => 'bar'), __NAMESPACE__.'\ObjectConstructorArgsWithPrivateMutatorDummy', 'any');
262 $this->assertEquals('bar', $obj->getFoo());
265 public function testGroupsNormalize()
267 $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
268 $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory);
269 $this->normalizer->setSerializer($this->serializer);
271 $obj = new GroupDummy();
274 $obj->setFooBar('fooBar');
275 $obj->setSymfony('symfony');
276 $obj->setKevin('kevin');
277 $obj->setCoopTilleuls('coopTilleuls');
279 $this->assertEquals(array(
281 ), $this->normalizer->normalize($obj, null, array(GetSetMethodNormalizer::GROUPS => array('c'))));
283 $this->assertEquals(array(
284 'symfony' => 'symfony',
286 'fooBar' => 'fooBar',
289 'coopTilleuls' => 'coopTilleuls',
290 ), $this->normalizer->normalize($obj, null, array(GetSetMethodNormalizer::GROUPS => array('a', 'c'))));
293 public function testGroupsDenormalize()
295 $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
296 $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory);
297 $this->normalizer->setSerializer($this->serializer);
299 $obj = new GroupDummy();
302 $toNormalize = array('foo' => 'foo', 'bar' => 'bar');
304 $normalized = $this->normalizer->denormalize(
306 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
308 array(GetSetMethodNormalizer::GROUPS => array('a'))
310 $this->assertEquals($obj, $normalized);
314 $normalized = $this->normalizer->denormalize(
316 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
318 array(GetSetMethodNormalizer::GROUPS => array('a', 'b'))
320 $this->assertEquals($obj, $normalized);
323 public function testGroupsNormalizeWithNameConverter()
325 $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
326 $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
327 $this->normalizer->setSerializer($this->serializer);
329 $obj = new GroupDummy();
330 $obj->setFooBar('@dunglas');
331 $obj->setSymfony('@coopTilleuls');
332 $obj->setCoopTilleuls('les-tilleuls.coop');
337 'foo_bar' => '@dunglas',
338 'symfony' => '@coopTilleuls',
340 $this->normalizer->normalize($obj, null, array(GetSetMethodNormalizer::GROUPS => array('name_converter')))
344 public function testGroupsDenormalizeWithNameConverter()
346 $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
347 $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
348 $this->normalizer->setSerializer($this->serializer);
350 $obj = new GroupDummy();
351 $obj->setFooBar('@dunglas');
352 $obj->setSymfony('@coopTilleuls');
356 $this->normalizer->denormalize(array(
358 'foo_bar' => '@dunglas',
359 'symfony' => '@coopTilleuls',
360 'coop_tilleuls' => 'les-tilleuls.coop',
361 ), 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, array(GetSetMethodNormalizer::GROUPS => array('name_converter')))
366 * @dataProvider provideCallbacks
368 public function testCallbacks($callbacks, $value, $result, $message)
370 $this->normalizer->setCallbacks($callbacks);
372 $obj = new GetConstructorDummy('', $value, true);
376 $this->normalizer->normalize($obj, 'any'),
382 * @expectedException \InvalidArgumentException
384 public function testUncallableCallbacks()
386 $this->normalizer->setCallbacks(array('bar' => null));
388 $obj = new GetConstructorDummy('baz', 'quux', true);
390 $this->normalizer->normalize($obj, 'any');
393 public function testIgnoredAttributes()
395 $this->normalizer->setIgnoredAttributes(array('foo', 'bar', 'baz', 'camelCase', 'object'));
397 $obj = new GetSetDummy();
403 array('fooBar' => 'foobar'),
404 $this->normalizer->normalize($obj, 'any')
408 public function provideCallbacks()
413 'bar' => function ($bar) {
418 array('foo' => '', 'bar' => 'baz', 'baz' => true),
423 'bar' => function ($bar) {
427 array('foo' => '', 'bar' => null, 'baz' => true),
432 'bar' => function ($bar) {
433 return $bar->format('d-m-Y H:i:s');
436 new \DateTime('2011-09-10 06:30:00'),
437 array('foo' => '', 'bar' => '10-09-2011 06:30:00', 'baz' => true),
442 'bar' => function ($bars) {
444 foreach ($bars as $bar) {
445 $foos .= $bar->getFoo();
451 array(new GetConstructorDummy('baz', '', false), new GetConstructorDummy('quux', '', false)),
452 array('foo' => '', 'bar' => 'bazquux', 'baz' => true),
453 'Collect a property',
457 'bar' => function ($bars) {
461 array(new GetConstructorDummy('baz', '', false), new GetConstructorDummy('quux', '', false)),
462 array('foo' => '', 'bar' => 2, 'baz' => true),
469 * @expectedException \Symfony\Component\Serializer\Exception\LogicException
470 * @expectedExceptionMessage Cannot normalize attribute "object" because injected serializer is not a normalizer
472 public function testUnableToNormalizeObjectAttribute()
474 $serializer = $this->getMockBuilder('Symfony\Component\Serializer\SerializerInterface')->getMock();
475 $this->normalizer->setSerializer($serializer);
477 $obj = new GetSetDummy();
478 $object = new \stdClass();
479 $obj->setObject($object);
481 $this->normalizer->normalize($obj, 'any');
485 * @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException
487 public function testUnableToNormalizeCircularReference()
489 $serializer = new Serializer(array($this->normalizer));
490 $this->normalizer->setSerializer($serializer);
491 $this->normalizer->setCircularReferenceLimit(2);
493 $obj = new CircularReferenceDummy();
495 $this->normalizer->normalize($obj);
498 public function testSiblingReference()
500 $serializer = new Serializer(array($this->normalizer));
501 $this->normalizer->setSerializer($serializer);
503 $siblingHolder = new SiblingHolder();
506 'sibling0' => array('coopTilleuls' => 'Les-Tilleuls.coop'),
507 'sibling1' => array('coopTilleuls' => 'Les-Tilleuls.coop'),
508 'sibling2' => array('coopTilleuls' => 'Les-Tilleuls.coop'),
510 $this->assertEquals($expected, $this->normalizer->normalize($siblingHolder));
513 public function testCircularReferenceHandler()
515 $serializer = new Serializer(array($this->normalizer));
516 $this->normalizer->setSerializer($serializer);
517 $this->normalizer->setCircularReferenceHandler(function ($obj) {
518 return get_class($obj);
521 $obj = new CircularReferenceDummy();
523 $expected = array('me' => 'Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy');
524 $this->assertEquals($expected, $this->normalizer->normalize($obj));
527 public function testObjectToPopulate()
529 $dummy = new GetSetDummy();
530 $dummy->setFoo('foo');
532 $obj = $this->normalizer->denormalize(
533 array('bar' => 'bar'),
534 __NAMESPACE__.'\GetSetDummy',
536 array(GetSetMethodNormalizer::OBJECT_TO_POPULATE => $dummy)
539 $this->assertEquals($dummy, $obj);
540 $this->assertEquals('foo', $obj->getFoo());
541 $this->assertEquals('bar', $obj->getBar());
544 public function testDenormalizeNonExistingAttribute()
548 $this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\GetSetDummy')
552 public function testDenormalizeShouldNotSetStaticAttribute()
554 $obj = $this->normalizer->denormalize(array('staticObject' => true), __NAMESPACE__.'\GetSetDummy');
556 $this->assertEquals(new GetSetDummy(), $obj);
557 $this->assertNull(GetSetDummy::getStaticObject());
560 public function testNoTraversableSupport()
562 $this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject()));
565 public function testNoStaticGetSetSupport()
567 $this->assertFalse($this->normalizer->supportsNormalization(new ObjectWithJustStaticSetterDummy()));
570 public function testPrivateSetter()
572 $obj = $this->normalizer->denormalize(array('foo' => 'foobar'), __NAMESPACE__.'\ObjectWithPrivateSetterDummy');
573 $this->assertEquals('bar', $obj->getFoo());
582 protected $camelCase;
584 private static $staticObject;
586 public function getFoo()
591 public function setFoo($foo)
596 public function getBar()
601 public function setBar($bar)
606 public function isBaz()
611 public function setBaz($baz)
616 public function getFooBar()
618 return $this->foo.$this->bar;
621 public function getCamelCase()
623 return $this->camelCase;
626 public function setCamelCase($camelCase)
628 $this->camelCase = $camelCase;
631 public function otherMethod()
633 throw new \RuntimeException('Dummy::otherMethod() should not be called');
636 public function setObject($object)
638 $this->object = $object;
641 public function getObject()
643 return $this->object;
646 public static function getStaticObject()
648 return self::$staticObject;
651 public static function setStaticObject($object)
653 self::$staticObject = $object;
656 protected function getPrivate()
658 throw new \RuntimeException('Dummy::getPrivate() should not be called');
662 class GetConstructorDummy
668 public function __construct($foo, $bar, $baz)
675 public function getFoo()
680 public function getBar()
685 public function isBaz()
690 public function otherMethod()
692 throw new \RuntimeException('Dummy::otherMethod() should not be called');
696 abstract class SerializerNormalizer implements SerializerInterface, NormalizerInterface
700 class GetConstructorOptionalArgsDummy
706 public function __construct($foo, $bar = array(), $baz = array())
713 public function getFoo()
718 public function getBar()
723 public function getBaz()
728 public function otherMethod()
730 throw new \RuntimeException('Dummy::otherMethod() should not be called');
734 class GetConstructorArgsWithDefaultValueDummy
739 public function __construct($foo = array(), $bar)
745 public function getFoo()
750 public function getBar()
755 public function otherMethod()
757 throw new \RuntimeException('Dummy::otherMethod() should not be called');
761 class GetCamelizedDummy
763 private $kevinDunglas;
767 public function __construct($kevinDunglas = null)
769 $this->kevinDunglas = $kevinDunglas;
772 public function getKevinDunglas()
774 return $this->kevinDunglas;
777 public function setFooBar($fooBar)
779 $this->fooBar = $fooBar;
782 public function getFooBar()
784 return $this->fooBar;
787 public function setBar_foo($bar_foo)
789 $this->bar_foo = $bar_foo;
792 public function getBar_foo()
794 return $this->bar_foo;
798 class ObjectConstructorArgsWithPrivateMutatorDummy
802 public function __construct($foo)
807 public function getFoo()
812 private function setFoo($foo)
818 class ObjectWithPrivateSetterDummy
820 private $foo = 'bar';
822 public function getFoo()
827 private function setFoo($foo)
832 class ObjectWithJustStaticSetterDummy
834 private static $foo = 'bar';
836 public static function getFoo()
841 public static function setFoo($foo)