|
13 | 13 |
|
14 | 14 | use PHPUnit\Framework\TestCase;
|
15 | 15 | use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
|
| 16 | +use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor; |
16 | 17 | use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
17 | 18 | use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
|
18 | 19 | use Symfony\Component\PropertyInfo\Type as LegacyType;
|
|
37 | 38 | use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
|
38 | 39 | use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
39 | 40 | use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
|
| 41 | +use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; |
40 | 42 | use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
|
41 | 43 | use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
|
42 | 44 | use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
@@ -1247,6 +1249,52 @@ protected function isAllowedAttribute($classOrObject, string $attribute, ?string
|
1247 | 1249 | $this->assertInstanceOf(\ArrayObject::class, $actual->foo);
|
1248 | 1250 | $this->assertSame(1, $actual->foo->count());
|
1249 | 1251 | }
|
| 1252 | + |
| 1253 | + public function testTemplateTypeWhenAnObjectIsPassedToDenormalize() |
| 1254 | + { |
| 1255 | + $normalizer = new class ( |
| 1256 | + classMetadataFactory: new ClassMetadataFactory(new AttributeLoader()), |
| 1257 | + propertyTypeExtractor: new PropertyInfoExtractor(typeExtractors: [new PhpStanExtractor(), new ReflectionExtractor()]) |
| 1258 | + ) extends AbstractObjectNormalizerDummy { |
| 1259 | + protected function isAllowedAttribute($classOrObject, string $attribute, ?string $format = null, array $context = []): bool |
| 1260 | + { |
| 1261 | + return true; |
| 1262 | + } |
| 1263 | + }; |
| 1264 | + $serializer = new Serializer([$normalizer]); |
| 1265 | + $normalizer->setSerializer($serializer); |
| 1266 | + |
| 1267 | + $denormalizedData = $normalizer->denormalize(['value' => new DummyGenericsValue()], DummyGenericsValueWrapper::class); |
| 1268 | + |
| 1269 | + $this->assertInstanceOf(DummyGenericsValueWrapper::class, $denormalizedData); |
| 1270 | + $this->assertInstanceOf(DummyGenericsValue::class, $denormalizedData->value); |
| 1271 | + |
| 1272 | + $this->assertSame('dummy', $denormalizedData->value->type); |
| 1273 | + } |
| 1274 | + |
| 1275 | + public function testDenormalizeTemplateType() |
| 1276 | + { |
| 1277 | + $normalizer = new class ( |
| 1278 | + classMetadataFactory: new ClassMetadataFactory(new AttributeLoader()), |
| 1279 | + propertyTypeExtractor: new PropertyInfoExtractor(typeExtractors: [new PhpStanExtractor(), new ReflectionExtractor()]) |
| 1280 | + ) extends AbstractObjectNormalizerDummy { |
| 1281 | + protected function isAllowedAttribute($classOrObject, string $attribute, ?string $format = null, array $context = []): bool |
| 1282 | + { |
| 1283 | + return true; |
| 1284 | + } |
| 1285 | + }; |
| 1286 | + $serializer = new Serializer([new ArrayDenormalizer(), $normalizer]); |
| 1287 | + $normalizer->setSerializer($serializer); |
| 1288 | + |
| 1289 | + $denormalizedData = $normalizer->denormalize(['value' => ['type' => 'dummy'], 'values' => [['type' => 'dummy']]], DummyGenericsValueWrapper::class); |
| 1290 | + |
| 1291 | + $this->assertInstanceOf(DummyGenericsValueWrapper::class, $denormalizedData); |
| 1292 | + $this->assertInstanceOf(DummyGenericsValue::class, $denormalizedData->value); |
| 1293 | + $this->assertContainsOnlyInstancesOf(DummyGenericsValue::class, $denormalizedData->values); |
| 1294 | + $this->assertCount(1, $denormalizedData->values); |
| 1295 | + $this->assertSame('dummy', $denormalizedData->value->type); |
| 1296 | + $this->assertSame('dummy', $denormalizedData->values[0]->type); |
| 1297 | + } |
1250 | 1298 | }
|
1251 | 1299 |
|
1252 | 1300 | class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
|
@@ -1753,3 +1801,31 @@ public function getSupportedTypes(?string $format): array
|
1753 | 1801 | ];
|
1754 | 1802 | }
|
1755 | 1803 | }
|
| 1804 | + |
| 1805 | +#[DiscriminatorMap('type', ['dummy' => DummyGenericsValue::class])] |
| 1806 | +abstract class AbstractDummyGenericsValue |
| 1807 | +{ |
| 1808 | + public function __construct( |
| 1809 | + public string $type, |
| 1810 | + ) { |
| 1811 | + } |
| 1812 | +} |
| 1813 | + |
| 1814 | +class DummyGenericsValue extends AbstractDummyGenericsValue |
| 1815 | +{ |
| 1816 | + public function __construct() |
| 1817 | + { |
| 1818 | + parent::__construct('dummy'); |
| 1819 | + } |
| 1820 | +} |
| 1821 | + |
| 1822 | +/** |
| 1823 | + * @template T of AbstractDummyGenericsValue |
| 1824 | + */ |
| 1825 | +class DummyGenericsValueWrapper |
| 1826 | +{ |
| 1827 | + /** @var T */ |
| 1828 | + public mixed $value; |
| 1829 | + /** @var T[] */ |
| 1830 | + public array $values; |
| 1831 | +} |
0 commit comments