@@ -168,6 +168,61 @@ public function testNormalize(): void
168168 ]));
169169 }
170170
171+ public function testNormalizeNullableToManyRelationReturnsNull (): void
172+ {
173+ $ dummy = new Dummy ();
174+ $ dummy ->setName ('foo ' );
175+
176+ $ propertyNameCollectionFactoryProphecy = $ this ->prophesize (PropertyNameCollectionFactoryInterface::class);
177+ $ propertyNameCollectionFactoryProphecy ->create (Dummy::class, Argument::type ('array ' ))->willReturn (new PropertyNameCollection (['name ' , 'relatedDummies ' ]));
178+
179+ // BC layer for api-platform/metadata < 4.1
180+ if (!method_exists (PropertyInfoExtractor::class, 'getType ' )) {
181+ $ relatedDummyType = new LegacyType (LegacyType::BUILTIN_TYPE_OBJECT , false , RelatedDummy::class);
182+ $ relatedDummiesType = new LegacyType (LegacyType::BUILTIN_TYPE_OBJECT , true , ArrayCollection::class, true , new LegacyType (LegacyType::BUILTIN_TYPE_INT ), $ relatedDummyType );
183+
184+ $ propertyMetadataFactoryProphecy = $ this ->prophesize (PropertyMetadataFactoryInterface::class);
185+ $ propertyMetadataFactoryProphecy ->create (Dummy::class, 'name ' , Argument::type ('array ' ))->willReturn ((new ApiProperty ())->withBuiltinTypes ([new LegacyType (LegacyType::BUILTIN_TYPE_STRING )])->withDescription ('' )->withReadable (true ));
186+ $ propertyMetadataFactoryProphecy ->create (Dummy::class, 'relatedDummies ' , Argument::type ('array ' ))->willReturn ((new ApiProperty ())->withBuiltinTypes ([$ relatedDummiesType ])->withReadable (true )->withWritable (false )->withReadableLink (false ));
187+ } else {
188+ $ relatedDummiesType = Type::nullable (Type::collection (Type::object (ArrayCollection::class), Type::object (RelatedDummy::class), Type::int ()));
189+
190+ $ propertyMetadataFactoryProphecy = $ this ->prophesize (PropertyMetadataFactoryInterface::class);
191+ $ propertyMetadataFactoryProphecy ->create (Dummy::class, 'name ' , Argument::type ('array ' ))->willReturn ((new ApiProperty ())->withNativeType (Type::string ())->withDescription ('' )->withReadable (true ));
192+ $ propertyMetadataFactoryProphecy ->create (Dummy::class, 'relatedDummies ' , Argument::type ('array ' ))->willReturn ((new ApiProperty ())->withNativeType ($ relatedDummiesType )->withReadable (true )->withWritable (false )->withReadableLink (false ));
193+ }
194+
195+ $ iriConverterProphecy = $ this ->prophesize (IriConverterInterface::class);
196+ $ iriConverterProphecy ->getIriFromResource ($ dummy , Argument::cetera ())->willReturn ('/dummies/1 ' );
197+
198+ $ propertyAccessorProphecy = $ this ->prophesize (PropertyAccessorInterface::class);
199+ $ propertyAccessorProphecy ->getValue ($ dummy , 'name ' )->willReturn ('foo ' );
200+ $ propertyAccessorProphecy ->getValue ($ dummy , 'relatedDummies ' )->willReturn (null );
201+
202+ $ resourceClassResolverProphecy = $ this ->prophesize (ResourceClassResolverInterface::class);
203+ $ resourceClassResolverProphecy ->getResourceClass (null , Dummy::class)->willReturn (Dummy::class);
204+ $ resourceClassResolverProphecy ->getResourceClass ($ dummy , null )->willReturn (Dummy::class);
205+ $ resourceClassResolverProphecy ->isResourceClass (Dummy::class)->willReturn (true );
206+ $ resourceClassResolverProphecy ->isResourceClass (RelatedDummy::class)->willReturn (true );
207+
208+ $ serializerProphecy = $ this ->prophesize (SerializerInterface::class);
209+ $ serializerProphecy ->willImplement (NormalizerInterface::class);
210+ $ serializerProphecy ->normalize ('foo ' , null , Argument::type ('array ' ))->willReturn ('foo ' );
211+ $ serializerProphecy ->normalize (null , null , Argument::type ('array ' ))->willReturn (null );
212+
213+ $ normalizer = new class ($ propertyNameCollectionFactoryProphecy ->reveal (), $ propertyMetadataFactoryProphecy ->reveal (), $ iriConverterProphecy ->reveal (), $ resourceClassResolverProphecy ->reveal (), $ propertyAccessorProphecy ->reveal (), null , null , [], null , null ) extends AbstractItemNormalizer {};
214+ $ normalizer ->setSerializer ($ serializerProphecy ->reveal ());
215+
216+ $ expected = [
217+ 'name ' => 'foo ' ,
218+ 'relatedDummies ' => null ,
219+ ];
220+ $ this ->assertSame ($ expected , $ normalizer ->normalize ($ dummy , null , [
221+ 'resources ' => [],
222+ 'skip_null_values ' => false ,
223+ ]));
224+ }
225+
171226 public function testNormalizeWithSecuredProperty (): void
172227 {
173228 $ dummy = new SecuredDummy ();
0 commit comments