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\PropertyInfo\Extractor\PhpDocExtractor;
17 use Symfony\Component\PropertyInfo\Type;
18 use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
19 use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
20 use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
21 use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
22 use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
23 use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
24 use Symfony\Component\Serializer\SerializerAwareInterface;
25 use Symfony\Component\Serializer\SerializerInterface;
27 class AbstractObjectNormalizerTest extends TestCase
29 public function testDenormalize()
31 $normalizer = new AbstractObjectNormalizerDummy();
32 $normalizedData = $normalizer->denormalize(array('foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'), __NAMESPACE__.'\Dummy');
34 $this->assertSame('foo', $normalizedData->foo);
35 $this->assertNull($normalizedData->bar);
36 $this->assertSame('baz', $normalizedData->baz);
39 public function testInstantiateObjectDenormalizer()
41 $data = array('foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz');
42 $class = __NAMESPACE__.'\Dummy';
45 $normalizer = new AbstractObjectNormalizerDummy();
47 $this->assertInstanceOf(__NAMESPACE__.'\Dummy', $normalizer->instantiateObject($data, $class, $context, new \ReflectionClass($class), array()));
51 * @expectedException \Symfony\Component\Serializer\Exception\ExtraAttributesException
52 * @expectedExceptionMessage Extra attributes are not allowed ("fooFoo", "fooBar" are unknown).
54 public function testDenormalizeWithExtraAttributes()
56 $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
57 $normalizer = new AbstractObjectNormalizerDummy($factory);
58 $normalizer->denormalize(
59 array('fooFoo' => 'foo', 'fooBar' => 'bar'),
60 __NAMESPACE__.'\Dummy',
62 array('allow_extra_attributes' => false)
67 * @expectedException \Symfony\Component\Serializer\Exception\ExtraAttributesException
68 * @expectedExceptionMessage Extra attributes are not allowed ("fooFoo", "fooBar" are unknown).
70 public function testDenormalizeWithExtraAttributesAndNoGroupsWithMetadataFactory()
72 $normalizer = new AbstractObjectNormalizerWithMetadata();
73 $normalizer->denormalize(
74 array('fooFoo' => 'foo', 'fooBar' => 'bar', 'bar' => 'bar'),
77 array('allow_extra_attributes' => false)
81 public function testDenormalizeCollectionDecodedFromXmlWithOneChild()
83 $denormalizer = $this->getDenormalizerForDummyCollection();
85 $dummyCollection = $denormalizer->denormalize(
91 DummyCollection::class,
95 $this->assertInstanceOf(DummyCollection::class, $dummyCollection);
96 $this->assertInternalType('array', $dummyCollection->children);
97 $this->assertCount(1, $dummyCollection->children);
98 $this->assertInstanceOf(DummyChild::class, $dummyCollection->children[0]);
101 public function testDenormalizeCollectionDecodedFromXmlWithTwoChildren()
103 $denormalizer = $this->getDenormalizerForDummyCollection();
105 $dummyCollection = $denormalizer->denormalize(
108 array('bar' => 'first'),
109 array('bar' => 'second'),
112 DummyCollection::class,
116 $this->assertInstanceOf(DummyCollection::class, $dummyCollection);
117 $this->assertInternalType('array', $dummyCollection->children);
118 $this->assertCount(2, $dummyCollection->children);
119 $this->assertInstanceOf(DummyChild::class, $dummyCollection->children[0]);
120 $this->assertInstanceOf(DummyChild::class, $dummyCollection->children[1]);
123 private function getDenormalizerForDummyCollection()
125 $extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
126 $extractor->method('getTypes')
127 ->will($this->onConsecutiveCalls(
135 new Type('object', false, DummyChild::class)
141 $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor);
142 $arrayDenormalizer = new ArrayDenormalizerDummy();
143 $serializer = new SerializerCollectionDummy(array($arrayDenormalizer, $denormalizer));
144 $arrayDenormalizer->setSerializer($serializer);
145 $denormalizer->setSerializer($serializer);
147 return $denormalizer;
151 * Test that additional attributes throw an exception if no metadata factory is specified.
153 * @expectedException \Symfony\Component\Serializer\Exception\LogicException
154 * @expectedExceptionMessage A class metadata factory must be provided in the constructor when setting "allow_extra_attributes" to false.
156 public function testExtraAttributesException()
158 $normalizer = new ObjectNormalizer();
160 $normalizer->denormalize(array(), \stdClass::class, 'xml', array(
161 'allow_extra_attributes' => false,
166 class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
168 protected function extractAttributes($object, $format = null, array $context = array())
172 protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
176 protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
178 $object->$attribute = $value;
181 protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array())
183 return \in_array($attribute, array('foo', 'baz'));
186 public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, $format = null)
188 return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes, $format);
199 class AbstractObjectNormalizerWithMetadata extends AbstractObjectNormalizer
201 public function __construct()
203 parent::__construct(new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())));
206 protected function extractAttributes($object, $format = null, array $context = array())
210 protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
214 protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
216 $object->$attribute = $value;
220 class DummyCollection
222 /** @var DummyChild[] */
231 class SerializerCollectionDummy implements SerializerInterface, DenormalizerInterface
233 private $normalizers;
236 * @param DenormalizerInterface[] $normalizers
238 public function __construct($normalizers)
240 $this->normalizers = $normalizers;
243 public function serialize($data, $format, array $context = array())
247 public function deserialize($data, $type, $format, array $context = array())
251 public function denormalize($data, $type, $format = null, array $context = array())
253 foreach ($this->normalizers as $normalizer) {
254 if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $type, $format, $context)) {
255 return $normalizer->denormalize($data, $type, $format, $context);
260 public function supportsDenormalization($data, $type, $format = null)
266 class AbstractObjectNormalizerCollectionDummy extends AbstractObjectNormalizer
268 protected function extractAttributes($object, $format = null, array $context = array())
272 protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
276 protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
278 $object->$attribute = $value;
281 protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array())
286 public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, $format = null)
288 return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes, $format);
291 public function serialize($data, $format, array $context = array())
295 public function deserialize($data, $type, $format, array $context = array())
300 class ArrayDenormalizerDummy implements DenormalizerInterface, SerializerAwareInterface
303 * @var SerializerInterface|DenormalizerInterface
310 * @throws NotNormalizableValueException
312 public function denormalize($data, $class, $format = null, array $context = array())
314 $serializer = $this->serializer;
315 $class = substr($class, 0, -2);
317 foreach ($data as $key => $value) {
318 $data[$key] = $serializer->denormalize($value, $class, $format, $context);
327 public function supportsDenormalization($data, $type, $format = null, array $context = array())
329 return '[]' === substr($type, -2)
330 && $this->serializer->supportsDenormalization($data, substr($type, 0, -2), $format, $context);
336 public function setSerializer(SerializerInterface $serializer)
338 $this->serializer = $serializer;