|
40 | 40 | use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\DummyWithMultipleRequiredConstructorArgs; |
41 | 41 | use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\DummyWithNullableConstructorArg; |
42 | 42 | use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\NonCloneableDummy; |
| 43 | +use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\NotificationType; |
43 | 44 | use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\PropertyCollectionIriOnly; |
44 | 45 | use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\PropertyCollectionIriOnlyRelation; |
45 | 46 | use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\RelatedDummy; |
@@ -1335,6 +1336,57 @@ public function testUnionTypeCollectionDenormalizationAcceptsAnyMember(): void |
1335 | 1336 | $this->assertInstanceOf(Dummy::class, $actual); |
1336 | 1337 | } |
1337 | 1338 |
|
| 1339 | + public function testDenormalizeNullableCollectionOfBackedEnums(): void |
| 1340 | + { |
| 1341 | + // Nullable collection value types (NullableType wrapping ObjectType/BackedEnumType) only exist |
| 1342 | + // in the native TypeInfo system. |
| 1343 | + if (!method_exists(PropertyInfoExtractor::class, 'getType')) { |
| 1344 | + $this->markTestSkipped('Requires symfony/property-info >= 7.1 (native types).'); |
| 1345 | + } |
| 1346 | + |
| 1347 | + $data = ['notificationType' => ['email']]; |
| 1348 | + |
| 1349 | + $propertyNameCollectionFactory = $this->createStub(PropertyNameCollectionFactoryInterface::class); |
| 1350 | + $propertyNameCollectionFactory->method('create')->willReturn(new PropertyNameCollection(['notificationType'])); |
| 1351 | + |
| 1352 | + // Mirrors what Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor produces for a nullable |
| 1353 | + // Doctrine SIMPLE_ARRAY column mapped with "enumType": both the collection and its value type |
| 1354 | + // end up wrapped in a NullableType. |
| 1355 | + $propertyMetadataFactory = $this->createStub(PropertyMetadataFactoryInterface::class); |
| 1356 | + $propertyMetadataFactory->method('create')->willReturn( |
| 1357 | + (new ApiProperty()) |
| 1358 | + ->withNativeType(Type::nullable(Type::list(Type::nullable(Type::enum(NotificationType::class))))) |
| 1359 | + ->withWritable(true) |
| 1360 | + ); |
| 1361 | + |
| 1362 | + $resourceClassResolver = $this->createStub(ResourceClassResolverInterface::class); |
| 1363 | + $resourceClassResolver->method('isResourceClass')->willReturnMap([ |
| 1364 | + [Dummy::class, true], |
| 1365 | + [NotificationType::class, false], |
| 1366 | + ]); |
| 1367 | + $resourceClassResolver->method('getResourceClass')->willReturnMap([ |
| 1368 | + [null, Dummy::class, Dummy::class], |
| 1369 | + ]); |
| 1370 | + |
| 1371 | + $propertyAccessor = $this->createMock(PropertyAccessorInterface::class); |
| 1372 | + $propertyAccessor->expects($this->once()) |
| 1373 | + ->method('setValue') |
| 1374 | + ->with($this->isInstanceOf(Dummy::class), 'notificationType', [NotificationType::Email]); |
| 1375 | + |
| 1376 | + $iriConverter = $this->createStub(IriConverterInterface::class); |
| 1377 | + |
| 1378 | + $serializerProphecy = $this->prophesize(SerializerInterface::class); |
| 1379 | + $serializerProphecy->willImplement(DenormalizerInterface::class); |
| 1380 | + $serializerProphecy->denormalize(['email'], NotificationType::class.'[]', null, Argument::type('array'))->willReturn([NotificationType::Email]); |
| 1381 | + |
| 1382 | + $normalizer = new class($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, null, null, [], null, null) extends AbstractItemNormalizer {}; |
| 1383 | + $normalizer->setSerializer($serializerProphecy->reveal()); |
| 1384 | + |
| 1385 | + $actual = $normalizer->denormalize($data, Dummy::class); |
| 1386 | + |
| 1387 | + $this->assertInstanceOf(Dummy::class, $actual); |
| 1388 | + } |
| 1389 | + |
1338 | 1390 | public function testTypeConfusionGuardPreservesPathAndExpectedType(): void |
1339 | 1391 | { |
1340 | 1392 | $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); |
|
0 commit comments