diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 0e3fda568ea9e..f4be086e76e26 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -202,7 +202,7 @@ public function getType(string $class, string $property, array $context = []): ? $type = $this->typeResolver->resolve($mutatorReflection->getParameters()[0]); if (!$type instanceof CollectionType && \in_array($prefix, $this->arrayMutatorPrefixes, true)) { - $type = Type::list($type); + $type = $this->isNullableProperty($class, $property) ? Type::nullable(Type::list($type)) : Type::list($type); } return $type; diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index 06fc50e5df39e..7d72f9c274618 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -164,6 +164,7 @@ public static function provideLegacyTypes() ['listOfStrings', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))], null, null], ['self', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], null, null], ['collectionAsObject', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyCollection::class, true, [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])], null, null], + ['nullableTypedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class))], null, null], ]; } @@ -548,6 +549,7 @@ public static function typeProvider(): iterable yield ['collection', Type::list(Type::object(\DateTimeImmutable::class)), null, null]; yield ['nestedCollection', Type::list(Type::list(Type::string())), null, null]; yield ['mixedCollection', Type::array(), null, null]; + yield ['nullableTypedCollection', Type::nullable(Type::list(Type::object(Dummy::class))), null, null]; yield ['a', Type::int(), 'A.', null]; yield ['b', Type::nullable(Type::object(ParentDummy::class)), 'B.', null]; yield ['c', Type::nullable(Type::bool()), null, null]; diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index d5e5c676727ed..02b4bd84824cf 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -76,6 +76,7 @@ public function testGetProperties() 'listOfStrings', 'parentAnnotation', 'genericInterface', + 'nullableTypedCollection', 'foo', 'foo2', 'foo3', @@ -143,6 +144,7 @@ public function testGetPropertiesWithCustomPrefixes() 'listOfStrings', 'parentAnnotation', 'genericInterface', + 'nullableTypedCollection', 'foo', 'foo2', 'foo3', @@ -199,6 +201,7 @@ public function testGetPropertiesWithNoPrefixes() 'listOfStrings', 'parentAnnotation', 'genericInterface', + 'nullableTypedCollection', 'foo', 'foo2', 'foo3', @@ -865,6 +868,7 @@ public function testTypedProperties() $this->assertEquals(Type::list(Type::string()), $this->extractor->getType(Php74Dummy::class, 'stringCollection')); $this->assertEquals(Type::nullable(Type::int()), $this->extractor->getType(Php74Dummy::class, 'nullableWithDefault')); $this->assertEquals(Type::array(), $this->extractor->getType(Php74Dummy::class, 'collection')); + $this->assertEquals(Type::nullable(Type::list(Type::object(Dummy::class))), $this->extractor->getType(Php74Dummy::class, 'nullableTypedCollection')); } /** diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index 8cd7464a7fe93..17a0b02a46ed1 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -177,6 +177,9 @@ class Dummy extends ParentDummy */ public $genericInterface; + /** @var Dummy[]|null */ + public $nullableTypedCollection = null; + public static function getStatic() { } @@ -269,4 +272,8 @@ public function addDate(\DateTimeImmutable $date) public function hasElement(string $element): bool { } + + public function addNullableTypedCollection(Dummy $dummy): void + { + } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php index 816b857b67b11..dc72d07756b88 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php @@ -23,6 +23,9 @@ class Php74Dummy private ?int $nullableWithDefault = 1; public array $collection = []; + /** @var Dummy[]|null */ + public ?array $nullableTypedCollection = null; + public function addStringCollection(string $string): void { } @@ -30,4 +33,8 @@ public function addStringCollection(string $string): void public function removeStringCollection(string $string): void { } + + public function addNullableTypedCollection(Dummy $dummy): void + { + } }