diff --git a/UPGRADE-8.0.md b/UPGRADE-8.0.md index 63b5f4fe245ab..1c61aae4cc07f 100644 --- a/UPGRADE-8.0.md +++ b/UPGRADE-8.0.md @@ -66,6 +66,21 @@ Console * Add method `isSilent()` to `OutputInterface` +DoctrineBridge +-------------- + + * Remove the `DoctrineExtractor::getTypes()` method, use `DoctrineExtractor::getType()` instead + + *Before* + ```php + $types = $extractor->getTypes(Foo::class, 'property'); + ``` + + *After* + ```php + $type = $extractor->getType(Foo::class, 'property'); + ``` + HttpClient ---------- @@ -91,6 +106,107 @@ OptionsResolver }); ``` +PropertyInfo +------------ + + * Remove the `PropertyTypeExtractorInterface::getTypes()` method, use `PropertyTypeExtractorInterface::getType()` instead + + *Before* + ```php + $types = $extractor->getTypes(Foo::class, 'property'); + ``` + + *After* + ```php + $type = $extractor->getType(Foo::class, 'property'); + ``` + + * Remove the `ConstructorArgumentTypeExtractorInterface::getTypesFromConstructor()` method, use `ConstructorArgumentTypeExtractorInterface::getTypeFromConstructor()` instead + + *Before* + ```php + $types = $extractor->getTypesFromConstructor(Foo::class, 'property'); + ``` + + *After* + ```php + $type = $extractor->getTypeFromConstructor(Foo::class, 'property'); + ``` + + * Remove the `Type` class, use `Symfony\Component\TypeInfo\Type` class from `symfony/type-info` instead + + *Before* + ```php + use Symfony\Component\PropertyInfo\Type; + + // create types + $int = [new Type(Type::BUILTIN_TYPE_INT)]; + $nullableString = [new Type(Type::BUILTIN_TYPE_STRING, true)]; + $object = [new Type(Type::BUILTIN_TYPE_OBJECT, false, Foo::class)]; + $boolList = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(BUILTIN_TYPE_INT), new Type(BUILTIN_TYPE_BOOL))]; + $union = [new Type(Type::BUILTIN_TYPE_STRING), new Type(BUILTIN_TYPE_INT)]; + $intersection = [new Type(Type::BUILTIN_TYPE_OBJECT, false, \Traversable::class), new Type(Type::BUILTIN_TYPE_OBJECT, false, \Stringable::class)]; + + // test if a type is nullable + $intIsNullable = $int[0]->isNullable(); + + // echo builtin types of union + foreach ($union as $type) { + echo $type->getBuiltinType(); + } + + // test if a type represents an instance of \ArrayAccess + if ($object[0]->getClassName() instanceof \ArrayAccess::class) { + // ... + } + + // handle collections + if ($boolList[0]->isCollection()) { + $k = $boolList->getCollectionKeyTypes(); + $v = $boolList->getCollectionValueTypes(); + + // ... + } + ``` + + *After* + ```php + use Symfony\Component\TypeInfo\BuiltinType; + use Symfony\Component\TypeInfo\CollectionType; + use Symfony\Component\TypeInfo\Type; + + // create types + $int = Type::int(); + $nullableString = Type::nullable(Type::string()); + $object = Type::object(Foo::class); + $boolList = Type::list(Type::bool()); + $union = Type::union(Type::string(), Type::int()); + $intersection = Type::intersection(Type::object(\Traversable::class), Type::object(\Stringable::class)); + + // test if a type is nullable + $intIsNullable = $int->isNullable(); + + // echo builtin types of union + foreach ($union->traverse() as $type) { + if ($type instanceof BuiltinType) { + echo $type->getTypeIdentifier()->value; + } + } + + // test if a type represents an instance of \ArrayAccess + if ($object->isIdentifiedBy(\ArrayAccess::class)) { + // ... + } + + // handle collections + if ($boolList instanceof CollectionType) { + $k = $boolList->getCollectionKeyType(); + $v = $boolList->getCollectionValueType(); + + // ... + } + ``` + TwigBridge ---------- diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 050b84acece96..c7e4709b1a197 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -25,7 +25,6 @@ use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeIdentifier; @@ -161,152 +160,6 @@ public function getType(string $class, string $property, array $context = []): ? }; } - /** - * @deprecated since Symfony 7.3, use "getType" instead - */ - public function getTypes(string $class, string $property, array $context = []): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - if (null === $metadata = $this->getMetadata($class)) { - return null; - } - - if ($metadata->hasAssociation($property)) { - $class = $metadata->getAssociationTargetClass($property); - - if ($metadata->isSingleValuedAssociation($property)) { - if ($metadata instanceof ClassMetadata) { - $associationMapping = $metadata->getAssociationMapping($property); - - $nullable = $this->isAssociationNullable($associationMapping); - } else { - $nullable = false; - } - - return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $class)]; - } - - $collectionKeyType = LegacyType::BUILTIN_TYPE_INT; - - if ($metadata instanceof ClassMetadata) { - $associationMapping = $metadata->getAssociationMapping($property); - - if (self::getMappingValue($associationMapping, 'indexBy')) { - $subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity')); - - // Check if indexBy value is a property - $fieldName = self::getMappingValue($associationMapping, 'indexBy'); - if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) { - $fieldName = $subMetadata->getFieldForColumn(self::getMappingValue($associationMapping, 'indexBy')); - // Not a property, maybe a column name? - if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) { - // Maybe the column name is the association join column? - $associationMapping = $subMetadata->getAssociationMapping($fieldName); - - $indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($fieldName); - $subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity')); - - // Not a property, maybe a column name? - if (null === ($typeOfField = $subMetadata->getTypeOfField($indexProperty))) { - $fieldName = $subMetadata->getFieldForColumn($indexProperty); - $typeOfField = $subMetadata->getTypeOfField($fieldName); - } - } - } - - if (!$collectionKeyType = $this->getTypeIdentifierLegacy($typeOfField)) { - return null; - } - } - } - - return [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - Collection::class, - true, - new LegacyType($collectionKeyType), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, $class) - )]; - } - - if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) { - return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, self::getMappingValue($metadata->embeddedClasses[$property], 'class'))]; - } - - if ($metadata->hasField($property)) { - $typeOfField = $metadata->getTypeOfField($property); - - if (!$builtinType = $this->getTypeIdentifierLegacy($typeOfField)) { - return null; - } - - $nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property); - - // DBAL 4 has a special fallback strategy for BINGINT (int -> string) - if (Types::BIGINT === $typeOfField && !method_exists(BigIntType::class, 'getName')) { - return [ - new LegacyType(LegacyType::BUILTIN_TYPE_INT, $nullable), - new LegacyType(LegacyType::BUILTIN_TYPE_STRING, $nullable), - ]; - } - - $enumType = null; - if (null !== $enumClass = self::getMappingValue($metadata->getFieldMapping($property), 'enumType') ?? null) { - $enumType = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $enumClass); - } - - switch ($builtinType) { - case LegacyType::BUILTIN_TYPE_OBJECT: - switch ($typeOfField) { - case Types::DATE_MUTABLE: - case Types::DATETIME_MUTABLE: - case Types::DATETIMETZ_MUTABLE: - case 'vardatetime': - case Types::TIME_MUTABLE: - return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')]; - - case Types::DATE_IMMUTABLE: - case Types::DATETIME_IMMUTABLE: - case Types::DATETIMETZ_IMMUTABLE: - case Types::TIME_IMMUTABLE: - return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateTimeImmutable')]; - - case Types::DATEINTERVAL: - return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateInterval')]; - } - - break; - case LegacyType::BUILTIN_TYPE_ARRAY: - switch ($typeOfField) { - case 'array': // DBAL < 4 - case 'json_array': // DBAL < 3 - // return null if $enumType is set, because we can't determine if collectionKeyType is string or int - if ($enumType) { - return null; - } - - return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true)]; - - case Types::SIMPLE_ARRAY: - return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), $enumType ?? new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]; - } - break; - case LegacyType::BUILTIN_TYPE_INT: - case LegacyType::BUILTIN_TYPE_STRING: - if ($enumType) { - return [$enumType]; - } - break; - } - - return [new LegacyType($builtinType, $nullable)]; - } - - return null; - } - public function isReadable(string $class, string $property, array $context = []): ?bool { return null; @@ -396,38 +249,6 @@ private function getTypeIdentifier(string $doctrineType): ?TypeIdentifier }; } - private function getTypeIdentifierLegacy(string $doctrineType): ?string - { - return match ($doctrineType) { - Types::SMALLINT, - Types::INTEGER => LegacyType::BUILTIN_TYPE_INT, - Types::FLOAT => LegacyType::BUILTIN_TYPE_FLOAT, - Types::BIGINT, - Types::STRING, - Types::TEXT, - Types::GUID, - Types::DECIMAL => LegacyType::BUILTIN_TYPE_STRING, - Types::BOOLEAN => LegacyType::BUILTIN_TYPE_BOOL, - Types::BLOB, - Types::BINARY => LegacyType::BUILTIN_TYPE_RESOURCE, - 'object', // DBAL < 4 - Types::DATE_MUTABLE, - Types::DATETIME_MUTABLE, - Types::DATETIMETZ_MUTABLE, - 'vardatetime', - Types::TIME_MUTABLE, - Types::DATE_IMMUTABLE, - Types::DATETIME_IMMUTABLE, - Types::DATETIMETZ_IMMUTABLE, - Types::TIME_IMMUTABLE, - Types::DATEINTERVAL => LegacyType::BUILTIN_TYPE_OBJECT, - 'array', // DBAL < 4 - 'json_array', // DBAL < 3 - Types::SIMPLE_ARRAY => LegacyType::BUILTIN_TYPE_ARRAY, - default => null, - }; - } - private static function getMappingValue(array|AssociationMapping|EmbeddedClassMapping|FieldMapping|JoinColumnMapping $mapping, string $key): mixed { if ($mapping instanceof AssociationMapping || $mapping instanceof EmbeddedClassMapping || $mapping instanceof FieldMapping || $mapping instanceof JoinColumnMapping) { diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index 04817d9389049..c5ae5cc470055 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -30,8 +30,6 @@ use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineWithEmbedded; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumInt; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumString; -use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; /** @@ -39,8 +37,6 @@ */ class DoctrineExtractorTest extends TestCase { - use ExpectUserDeprecationMessageTrait; - private function createExtractor(): DoctrineExtractor { $config = ORMSetup::createConfiguration(true); @@ -110,166 +106,11 @@ public function testTestGetPropertiesWithEmbedded() ); } - /** - * @group legacy - * - * @dataProvider legacyTypesProvider - */ - public function testExtractLegacy(string $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getTypes()" method is deprecated, use "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->createExtractor()->getTypes(DoctrineDummy::class, $property, [])); - } - - /** - * @group legacy - */ - public function testExtractWithEmbeddedLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getTypes()" method is deprecated, use "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getType()" instead.'); - - $expectedTypes = [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - DoctrineEmbeddable::class - )]; - - $actualTypes = $this->createExtractor()->getTypes( - DoctrineWithEmbedded::class, - 'embedded', - [] - ); - - $this->assertEquals($expectedTypes, $actualTypes); - } - - /** - * @group legacy - */ - public function testExtractEnumLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getTypes()" method is deprecated, use "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getType()" instead.'); - - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, EnumString::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumString', [])); - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, EnumInt::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumInt', [])); - $this->assertNull($this->createExtractor()->getTypes(DoctrineEnum::class, 'enumStringArray', [])); - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, EnumInt::class))], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumIntArray', [])); - $this->assertNull($this->createExtractor()->getTypes(DoctrineEnum::class, 'enumCustom', [])); - } - - /** - * @group legacy - */ - public static function legacyTypesProvider(): array - { - // DBAL 4 has a special fallback strategy for BINGINT (int -> string) - if (!method_exists(BigIntType::class, 'getName')) { - $expectedBingIntType = [new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]; - } else { - $expectedBingIntType = [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]; - } - - return [ - ['id', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['guid', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ['bigint', $expectedBingIntType], - ['time', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTime')]], - ['timeImmutable', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]], - ['dateInterval', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateInterval')]], - ['float', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]], - ['decimal', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ['bool', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]], - ['binary', [new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE)]], - ['jsonArray', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true)]], - ['foo', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')]], - ['bar', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - 'Doctrine\Common\Collections\Collection', - true, - new LegacyType(LegacyType::BUILTIN_TYPE_INT), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation') - )]], - ['indexedRguid', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - 'Doctrine\Common\Collections\Collection', - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation') - )]], - ['indexedBar', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - 'Doctrine\Common\Collections\Collection', - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation') - )]], - ['indexedFoo', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - 'Doctrine\Common\Collections\Collection', - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation') - )]], - ['indexedBaz', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - Collection::class, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_INT), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class) - )]], - ['simpleArray', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - ['customFoo', null], - ['notMapped', null], - ['indexedByDt', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - Collection::class, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class) - )]], - ['indexedByCustomType', null], - ['indexedBuz', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - Collection::class, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class) - )]], - ['dummyGeneratedValueList', [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - 'Doctrine\Common\Collections\Collection', - true, - new LegacyType(LegacyType::BUILTIN_TYPE_INT), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class) - )]], - ['json', null], - ]; - } - public function testGetPropertiesCatchException() { $this->assertNull($this->createExtractor()->getProperties('Not\Exist')); } - /** - * @group legacy - */ - public function testGetTypesCatchExceptionLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getTypes()" method is deprecated, use "Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor::getType()" instead.'); - - $this->assertNull($this->createExtractor()->getTypes('Not\Exist', 'baz')); - } - public function testGeneratedValueNotWritable() { $extractor = $this->createExtractor(); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php index 18cd61b08519c..bf1c11cb57fb8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php @@ -11,7 +11,6 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; class PropertyInfoTest extends AbstractWebTestCase @@ -28,22 +27,6 @@ public function testPhpDocPriority() $this->assertEquals(Type::list(Type::int()), $propertyInfo->getType(Dummy::class, 'codes')); } - - /** - * @group legacy - */ - public function testPhpDocPriorityLegacy() - { - static::bootKernel(['test_case' => 'Serializer']); - - $propertyInfo = static::getContainer()->get('property_info'); - - if (!method_exists($propertyInfo, 'getTypes')) { - $this->markTestSkipped(); - } - - $this->assertEquals([new LegacyType('array', false, null, true, new LegacyType('int'), new LegacyType('int'))], $propertyInfo->getTypes(Dummy::class, 'codes')); - } } class Dummy diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php index 57695d8312114..7017b1540ef49 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php @@ -11,7 +11,6 @@ namespace Symfony\Component\PropertyInfo\Extractor; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; /** @@ -21,15 +20,6 @@ */ interface ConstructorArgumentTypeExtractorInterface { - /** - * Gets types of an argument from constructor. - * - * @deprecated since Symfony 7.3, use "getTypeFromConstructor" instead - * - * @return LegacyType[]|null - */ - public function getTypesFromConstructor(string $class, string $property): ?array; - /** * Gets type of an argument from constructor. * diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php index 106158beeaa1e..89721d57db402 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php @@ -39,21 +39,4 @@ public function getType(string $class, string $property, array $context = []): ? return null; } - - /** - * @deprecated since Symfony 7.3, use "getType" instead - */ - public function getTypes(string $class, string $property, array $context = []): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - foreach ($this->extractors as $extractor) { - $value = $extractor->getTypesFromConstructor($class, $property); - if (null !== $value) { - return $value; - } - } - - return null; - } } diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 5ee3097851d19..1185d20aca2d7 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -20,7 +20,6 @@ use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface; use Symfony\Component\PropertyInfo\PropertyDocBlockExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\PropertyInfo\Util\PhpDocTypeHelper; use Symfony\Component\TypeInfo\Exception\LogicException; use Symfony\Component\TypeInfo\Type; @@ -118,92 +117,6 @@ public function getLongDescription(string $class, string $property, array $conte return '' === $contents ? null : $contents; } - /** - * @deprecated since Symfony 7.3, use "getType" instead - */ - public function getTypes(string $class, string $property, array $context = []): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - /** @var DocBlock $docBlock */ - [$docBlock, $source, $prefix] = $this->findDocBlock($class, $property); - if (!$docBlock) { - return null; - } - - $tag = match ($source) { - self::PROPERTY => 'var', - self::ACCESSOR => 'return', - self::MUTATOR => 'param', - }; - - $parentClass = null; - $types = []; - /** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */ - foreach ($docBlock->getTagsByName($tag) as $tag) { - if ($tag && !$tag instanceof InvalidTag && null !== $tag->getType()) { - foreach ($this->phpDocTypeHelper->getTypes($tag->getType()) as $type) { - switch ($type->getClassName()) { - case 'self': - case 'static': - $resolvedClass = $class; - break; - - case 'parent': - if (false !== $resolvedClass = $parentClass ??= get_parent_class($class)) { - break; - } - // no break - - default: - $types[] = $type; - continue 2; - } - - $types[] = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $type->isNullable(), $resolvedClass, $type->isCollection(), $type->getCollectionKeyTypes(), $type->getCollectionValueTypes()); - } - } - } - - if (!isset($types[0])) { - return null; - } - - if (!\in_array($prefix, $this->arrayMutatorPrefixes, true)) { - return $types; - } - - return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), $types[0])]; - } - - /** - * @deprecated since Symfony 7.3, use "getTypeFromConstructor" instead - */ - public function getTypesFromConstructor(string $class, string $property): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getTypeFromConstructor()" instead.', __METHOD__, self::class); - - $docBlock = $this->getDocBlockFromConstructor($class, $property); - - if (!$docBlock) { - return null; - } - - $types = []; - /** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */ - foreach ($docBlock->getTagsByName('param') as $tag) { - if ($tag && null !== $tag->getType()) { - $types[] = $this->phpDocTypeHelper->getTypes($tag->getType()); - } - } - - if (!isset($types[0]) || [] === $types[0]) { - return null; - } - - return array_merge([], ...$types); - } - public function getType(string $class, string $property, array $context = []): ?Type { /** @var DocBlock $docBlock */ diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php index afe29bec26117..35552f253d558 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php @@ -12,7 +12,6 @@ namespace Symfony\Component\PropertyInfo\Extractor; use phpDocumentor\Reflection\Types\ContextFactory; -use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode; @@ -28,8 +27,6 @@ use PHPStan\PhpDocParser\ParserConfig; use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; -use Symfony\Component\PropertyInfo\Util\PhpStanTypeHelper; use Symfony\Component\TypeInfo\Exception\UnsupportedException; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeContext\TypeContext; @@ -55,7 +52,6 @@ final class PhpStanExtractor implements PropertyDescriptionExtractorInterface, P /** @var array */ private array $docBlocks = []; - private PhpStanTypeHelper $phpStanTypeHelper; private array $mutatorPrefixes; private array $accessorPrefixes; private array $arrayMutatorPrefixes; @@ -78,7 +74,6 @@ public function __construct(?array $mutatorPrefixes = null, ?array $accessorPref throw new \LogicException(\sprintf('Unable to use the "%s" class as the "phpstan/phpdoc-parser" package is not installed. Try running composer require "phpstan/phpdoc-parser".', __CLASS__)); } - $this->phpStanTypeHelper = new PhpStanTypeHelper(); $this->mutatorPrefixes = $mutatorPrefixes ?? ReflectionExtractor::$defaultMutatorPrefixes; $this->accessorPrefixes = $accessorPrefixes ?? ReflectionExtractor::$defaultAccessorPrefixes; $this->arrayMutatorPrefixes = $arrayMutatorPrefixes ?? ReflectionExtractor::$defaultArrayMutatorPrefixes; @@ -95,108 +90,6 @@ public function __construct(?array $mutatorPrefixes = null, ?array $accessorPref $this->typeContextFactory = new TypeContextFactory($this->stringTypeResolver); } - /** - * @deprecated since Symfony 7.3, use "getType" instead - */ - public function getTypes(string $class, string $property, array $context = []): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - /** @var PhpDocNode|null $docNode */ - [$docNode, $source, $prefix, $declaringClass] = $this->getDocBlock($class, $property); - if (null === $docNode) { - return null; - } - - switch ($source) { - case self::PROPERTY: - $tag = '@var'; - break; - - case self::ACCESSOR: - $tag = '@return'; - break; - - case self::MUTATOR: - $tag = '@param'; - break; - } - - $parentClass = null; - $types = []; - foreach ($docNode->getTagsByName($tag) as $tagDocNode) { - if ($tagDocNode->value instanceof InvalidTagValueNode) { - continue; - } - - if ( - $tagDocNode->value instanceof ParamTagValueNode - && null === $prefix - && $tagDocNode->value->parameterName !== '$'.$property - ) { - continue; - } - - $typeContext = $this->contexts[$class.'/'.$declaringClass] ??= $this->typeContextFactory->createFromClassName($class, $declaringClass); - - foreach ($this->phpStanTypeHelper->getTypes($tagDocNode->value, $typeContext) as $type) { - switch ($type->getClassName()) { - case 'self': - case 'static': - $resolvedClass = $class; - break; - - case 'parent': - if (false !== $resolvedClass = $parentClass ??= get_parent_class($class)) { - break; - } - // no break - - default: - $types[] = $type; - continue 2; - } - - $types[] = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $type->isNullable(), $resolvedClass, $type->isCollection(), $type->getCollectionKeyTypes(), $type->getCollectionValueTypes()); - } - } - - if (!isset($types[0])) { - return null; - } - - if (!\in_array($prefix, $this->arrayMutatorPrefixes, true)) { - return $types; - } - - return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), $types[0])]; - } - - /** - * @deprecated since Symfony 7.3, use "getTypeFromConstructor" instead - * - * @return LegacyType[]|null - */ - public function getTypesFromConstructor(string $class, string $property): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getTypeFromConstructor()" instead.', __METHOD__, self::class); - - if (null === $tagDocNode = $this->getDocBlockFromConstructor($class, $property)) { - return null; - } - - $types = []; - foreach ($this->phpStanTypeHelper->getTypes($tagDocNode, $this->typeContextFactory->createFromClassName($class)) as $type) { - $types[] = $type; - } - - if (!isset($types[0])) { - return null; - } - - return $types; - } - public function getType(string $class, string $property, array $context = []): ?Type { /** @var PhpDocNode|null $docNode */ diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 78a37e257f470..9cab1b41986d4 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -19,7 +19,6 @@ use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\PropertyWriteInfo; use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\String\Inflector\EnglishInflector; use Symfony\Component\String\Inflector\InflectorInterface; use Symfony\Component\TypeInfo\Exception\UnsupportedException; @@ -155,65 +154,6 @@ public function getProperties(string $class, array $context = []): ?array return $properties ? array_values($properties) : null; } - /** - * @deprecated since Symfony 7.3, use "getType" instead - */ - public function getTypes(string $class, string $property, array $context = []): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - if ($fromMutator = $this->extractFromMutator($class, $property)) { - return $fromMutator; - } - - if ($fromAccessor = $this->extractFromAccessor($class, $property)) { - return $fromAccessor; - } - - if ( - ($context['enable_constructor_extraction'] ?? $this->enableConstructorExtraction) - && $fromConstructor = $this->extractFromConstructor($class, $property) - ) { - return $fromConstructor; - } - - if ($fromPropertyDeclaration = $this->extractFromPropertyDeclaration($class, $property)) { - return $fromPropertyDeclaration; - } - - return null; - } - - /** - * @deprecated since Symfony 7.3, use "getTypeFromConstructor" instead - * - * @return LegacyType[]|null - */ - public function getTypesFromConstructor(string $class, string $property): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getTypeFromConstructor()" instead.', __METHOD__, self::class); - - try { - $reflection = new \ReflectionClass($class); - } catch (\ReflectionException) { - return null; - } - if (!$reflectionConstructor = $reflection->getConstructor()) { - return null; - } - if (!$reflectionParameter = $this->getReflectionParameterFromConstructor($property, $reflectionConstructor)) { - return null; - } - if (!$reflectionType = $reflectionParameter->getType()) { - return null; - } - if (!$types = $this->extractFromReflectionType($reflectionType, $reflectionConstructor->getDeclaringClass())) { - return null; - } - - return $types; - } - public function getType(string $class, string $property, array $context = []): ?Type { [$mutatorReflection, $prefix] = $this->getMutatorMethod($class, $property); @@ -522,116 +462,6 @@ public function getWriteInfo(string $class, string $property, array $context = [ return $noneProperty; } - /** - * @return LegacyType[]|null - */ - private function extractFromMutator(string $class, string $property): ?array - { - [$reflectionMethod, $prefix] = $this->getMutatorMethod($class, $property); - if (null === $reflectionMethod) { - return null; - } - - $reflectionParameters = $reflectionMethod->getParameters(); - $reflectionParameter = $reflectionParameters[0]; - - if (!$reflectionType = $reflectionParameter->getType()) { - return null; - } - $type = $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass()); - - if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes, true)) { - $type = [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $this->isNullableProperty($class, $property), null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), $type[0])]; - } - - return $type; - } - - /** - * Tries to extract type information from accessors. - * - * @return LegacyType[]|null - */ - private function extractFromAccessor(string $class, string $property): ?array - { - [$reflectionMethod, $prefix] = $this->getAccessorMethod($class, $property); - if (null === $reflectionMethod) { - return null; - } - - if ($reflectionType = $reflectionMethod->getReturnType()) { - return $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass()); - } - - if (\in_array($prefix, ['is', 'can', 'has'])) { - return [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]; - } - - return null; - } - - /** - * Tries to extract type information from constructor. - * - * @return LegacyType[]|null - */ - private function extractFromConstructor(string $class, string $property): ?array - { - try { - $reflectionClass = new \ReflectionClass($class); - } catch (\ReflectionException) { - return null; - } - - $constructor = $reflectionClass->getConstructor(); - - if (!$constructor) { - return null; - } - - foreach ($constructor->getParameters() as $parameter) { - if ($property !== $parameter->name) { - continue; - } - $reflectionType = $parameter->getType(); - - return $reflectionType ? $this->extractFromReflectionType($reflectionType, $constructor->getDeclaringClass()) : null; - } - - if ($parentClass = $reflectionClass->getParentClass()) { - return $this->extractFromConstructor($parentClass->getName(), $property); - } - - return null; - } - - private function extractFromPropertyDeclaration(string $class, string $property): ?array - { - try { - $reflectionClass = new \ReflectionClass($class); - - $reflectionProperty = $reflectionClass->getProperty($property); - $reflectionPropertyType = $reflectionProperty->getType(); - - if (null !== $reflectionPropertyType && $types = $this->extractFromReflectionType($reflectionPropertyType, $reflectionProperty->getDeclaringClass())) { - return $types; - } - } catch (\ReflectionException) { - return null; - } - - $defaultValue = $reflectionClass->getDefaultProperties()[$property] ?? null; - - if (null === $defaultValue) { - return null; - } - - $type = \gettype($defaultValue); - $type = static::MAP_TYPES[$type] ?? $type; - - return [new LegacyType($type, $this->isNullableProperty($class, $property), null, LegacyType::BUILTIN_TYPE_ARRAY === $type)]; - } - private function extractTypeFromConstructor(\ReflectionClass $reflectionClass, string $property): ?Type { if (!$constructor = $reflectionClass->getConstructor()) { @@ -656,48 +486,6 @@ private function extractTypeFromConstructor(\ReflectionClass $reflectionClass, s return null; } - private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionClass $declaringClass): array - { - $types = []; - $nullable = $reflectionType->allowsNull(); - - foreach (($reflectionType instanceof \ReflectionUnionType || $reflectionType instanceof \ReflectionIntersectionType) ? $reflectionType->getTypes() : [$reflectionType] as $type) { - if (!$type instanceof \ReflectionNamedType) { - // Nested composite types are not supported yet. - return []; - } - - $phpTypeOrClass = $type->getName(); - if ('null' === $phpTypeOrClass || 'mixed' === $phpTypeOrClass || 'never' === $phpTypeOrClass) { - continue; - } - - if (LegacyType::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { - $types[] = new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true); - } elseif ('void' === $phpTypeOrClass) { - $types[] = new LegacyType(LegacyType::BUILTIN_TYPE_NULL, $nullable); - } elseif ($type->isBuiltin()) { - $types[] = new LegacyType($phpTypeOrClass, $nullable); - } else { - $types[] = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $declaringClass)); - } - } - - return $types; - } - - private function resolveTypeName(string $name, \ReflectionClass $declaringClass): string - { - if ('self' === $lcName = strtolower($name)) { - return $declaringClass->name; - } - if ('parent' === $lcName && $parent = $declaringClass->getParentClass()) { - return $parent->name; - } - - return $name; - } - private function isNullableProperty(string $class, string $property): bool { try { diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php index 866c38e99eb40..5cf0a6b4f5023 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php @@ -12,7 +12,6 @@ namespace Symfony\Component\PropertyInfo; use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\PropertyInfo\Util\LegacyTypeConverter; use Symfony\Component\TypeInfo\Type; /** @@ -63,11 +62,7 @@ public function getType(string $class, string $property, array $context = []): ? $serializedArguments = serialize([$class, $property, $context]); } catch (\Exception) { // If arguments are not serializable, skip the cache - if (method_exists($this->propertyInfoExtractor, 'getType')) { - return $this->propertyInfoExtractor->getType($class, $property, $context); - } - - return LegacyTypeConverter::toTypeInfoType($this->propertyInfoExtractor->getTypes($class, $property, $context)); + return $this->propertyInfoExtractor->getType($class, $property, $context); } // Calling rawurlencode escapes special characters not allowed in PSR-6's keys @@ -83,11 +78,7 @@ public function getType(string $class, string $property, array $context = []): ? return $this->arrayCache[$key] = $item->get(); } - if (method_exists($this->propertyInfoExtractor, 'getType')) { - $value = $this->propertyInfoExtractor->getType($class, $property, $context); - } else { - $value = LegacyTypeConverter::toTypeInfoType($this->propertyInfoExtractor->getTypes($class, $property, $context)); - } + $value = $this->propertyInfoExtractor->getType($class, $property, $context); $item->set($value); $this->cacheItemPool->save($item); @@ -95,16 +86,6 @@ public function getType(string $class, string $property, array $context = []): ? return $this->arrayCache[$key] = $value; } - /** - * @deprecated since Symfony 7.3, use "getType" instead - */ - public function getTypes(string $class, string $property, array $context = []): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - return $this->extract('getTypes', [$class, $property, $context]); - } - public function isInitializable(string $class, string $property, array $context = []): ?bool { return $this->extract('isInitializable', [$class, $property, $context]); diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php index 5a54854bfbba4..021074b105494 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php @@ -11,7 +11,6 @@ namespace Symfony\Component\PropertyInfo; -use Symfony\Component\PropertyInfo\Util\LegacyTypeConverter; use Symfony\Component\TypeInfo\Type; /** @@ -57,16 +56,6 @@ public function getLongDescription(string $class, string $property, array $conte public function getType(string $class, string $property, array $context = []): ?Type { foreach ($this->typeExtractors as $extractor) { - if (!method_exists($extractor, 'getType')) { - $legacyTypes = $extractor->getTypes($class, $property, $context); - - if (null !== $legacyTypes) { - return LegacyTypeConverter::toTypeInfoType($legacyTypes); - } - - continue; - } - if (null !== $value = $extractor->getType($class, $property, $context)) { return $value; } @@ -75,16 +64,6 @@ public function getType(string $class, string $property, array $context = []): ? return null; } - /** - * @deprecated since Symfony 7.3, use "getType" instead - */ - public function getTypes(string $class, string $property, array $context = []): ?array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - return $this->extract($this->typeExtractors, 'getTypes', [$class, $property, $context]); - } - public function isReadable(string $class, string $property, array $context = []): ?bool { return $this->extract($this->accessExtractors, 'isReadable', [$class, $property, $context]); diff --git a/src/Symfony/Component/PropertyInfo/PropertyTypeExtractorInterface.php b/src/Symfony/Component/PropertyInfo/PropertyTypeExtractorInterface.php index 358c08dd61c52..d1ba3f54b37f0 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyTypeExtractorInterface.php +++ b/src/Symfony/Component/PropertyInfo/PropertyTypeExtractorInterface.php @@ -11,24 +11,18 @@ namespace Symfony\Component\PropertyInfo; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; /** * Type Extractor Interface. * * @author Kévin Dunglas - * - * @method Type|null getType(string $class, string $property, array $context = []) */ interface PropertyTypeExtractorInterface { /** - * Gets types of a property. - * - * @deprecated since Symfony 7.3, use "getType" instead - * - * @return LegacyType[]|null + * @param class-string $class + * @param array $context */ - public function getTypes(string $class, string $property, array $context = []): ?array; + public function getType(string $class, string $property, array $context = []): ?Type; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php index 6f5c67131124e..c62d2aa3a0432 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/AbstractPropertyInfoExtractorTest.php @@ -20,7 +20,6 @@ use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\NullExtractor; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; /** @@ -60,14 +59,6 @@ public function testGetType() $this->assertEquals(Type::int(), $this->propertyInfo->getType('Foo', 'bar', [])); } - /** - * @group legacy - */ - public function testGetTypes() - { - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_INT)], $this->propertyInfo->getTypes('Foo', 'bar', [])); - } - public function testIsReadable() { $this->assertTrue($this->propertyInfo->isReadable('Foo', 'bar', [])); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php index 6f6b7849f59b9..ef4df5bb87754 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php @@ -12,10 +12,8 @@ namespace Symfony\Component\PropertyInfo\Tests\Extractor; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; use Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyExtractor; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; /** @@ -23,8 +21,6 @@ */ class ConstructorExtractorTest extends TestCase { - use ExpectUserDeprecationMessageTrait; - private ConstructorExtractor $extractor; protected function setUp(): void @@ -47,25 +43,4 @@ public function testGetTypeIfNoExtractors() $extractor = new ConstructorExtractor([]); $this->assertNull($extractor->getType('Foo', 'bar', [])); } - - /** - * @group legacy - */ - public function testGetTypes() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor::getType()" instead.'); - - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], $this->extractor->getTypes('Foo', 'bar', [])); - } - - /** - * @group legacy - */ - public function testGetTypesIfNoExtractors() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor::getType()" instead.'); - - $extractor = new ConstructorExtractor([]); - $this->assertNull($extractor->getTypes('Foo', 'bar', [])); - } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index f86527ad59f01..2ce504c46a7fd 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -13,7 +13,6 @@ use phpDocumentor\Reflection\DocBlock; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback; @@ -26,7 +25,6 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\PseudoTypesDummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\NullableType; @@ -35,8 +33,6 @@ */ class PhpDocExtractorTest extends TestCase { - use ExpectUserDeprecationMessageTrait; - private PhpDocExtractor $extractor; protected function setUp(): void @@ -44,20 +40,6 @@ protected function setUp(): void $this->extractor = new PhpDocExtractor(); } - /** - * @group legacy - * - * @dataProvider provideLegacyTypes - */ - public function testExtractLegacy($property, ?array $type, $shortDescription, $longDescription) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes(Dummy::class, $property)); - $this->assertSame($shortDescription, $this->extractor->getShortDescription(Dummy::class, $property)); - $this->assertSame($longDescription, $this->extractor->getLongDescription(Dummy::class, $property)); - } - public function testGetDocBlock() { $docBlock = $this->extractor->getDocBlock(Dummy::class, 'g'); @@ -71,490 +53,11 @@ public function testGetDocBlock() $this->assertNull($docBlock); } - /** - * @group legacy - */ - public function testParamTagTypeIsOmittedLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertNull($this->extractor->getTypes(OmittedParamTagTypeDocBlock::class, 'omittedType')); - } - - public static function provideLegacyInvalidTypes() - { - return [ - 'pub' => ['pub', null, null], - 'stat' => ['stat', null, null], - 'bar' => ['bar', 'Bar.', null], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyInvalidTypes - */ - public function testInvalidLegacy($property, $shortDescription, $longDescription) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property)); - $this->assertSame($shortDescription, $this->extractor->getShortDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property)); - $this->assertSame($longDescription, $this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property)); - } - - /** - * @group legacy - */ - public function testEmptyParamAnnotationLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', 'foo')); - $this->assertSame('Foo.', $this->extractor->getShortDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', 'foo')); - $this->assertNull($this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', 'foo')); - } - - /** - * @group legacy - * - * @dataProvider provideLegacyTypesWithNoPrefixes - */ - public function testExtractTypesWithNoPrefixesLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $noPrefixExtractor = new PhpDocExtractor(null, [], [], []); - - $this->assertEquals($type, $noPrefixExtractor->getTypes(Dummy::class, $property)); - } - - public static function provideLegacyTypes() - { - return [ - ['foo', null, 'Short description.', 'Long description.'], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], 'This is bar', null], - ['baz', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], 'Should be used.', null], - ['foo2', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)], null, null], - ['foo3', [new LegacyType(LegacyType::BUILTIN_TYPE_CALLABLE)], null, null], - ['foo4', [new LegacyType(LegacyType::BUILTIN_TYPE_NULL)], null, null], - ['foo5', null, null, null], - [ - 'files', - [ - new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), - new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE), - ], - null, - null, - ], - ['bal', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')], 'A short description ignoring template.', "A long description...\n\n...over several lines."], - ['parent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')], null, null], - ['collection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))], null, null], - ['nestedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)))], null, null], - ['mixedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, null, null)], null, null], - ['a', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], 'A.', null], - ['b', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')], 'B.', null], - ['c', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL, true)], null, null], - ['ct', [new LegacyType(LegacyType::BUILTIN_TYPE_TRUE, true)], null, null], - ['cf', [new LegacyType(LegacyType::BUILTIN_TYPE_FALSE, true)], null, null], - ['d', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)], null, null], - ['dt', [new LegacyType(LegacyType::BUILTIN_TYPE_TRUE)], null, null], - ['df', [new LegacyType(LegacyType::BUILTIN_TYPE_FALSE)], null, null], - ['e', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE))], null, null], - ['f', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))], null, null], - ['g', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)], 'Nullable array.', null], - ['h', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true)], null, null], - ['i', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true), new LegacyType(LegacyType::BUILTIN_TYPE_INT, true)], null, null], - ['j', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')], null, null], - ['nullableCollectionOfNonNullableElements', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_INT, false))], null, null], - ['donotexist', null, null, null], - ['staticGetter', null, null, null], - ['staticSetter', null, null, null], - ['emptyVar', null, 'This should not be removed.', null], - ['arrayWithKeys', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))], null, null], - ['arrayOfMixed', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_STRING), null)], null, null], - ['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], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyCollectionTypes - */ - public function testExtractCollectionLegacy($property, ?array $type, $shortDescription, $longDescription) - { - $this->testExtractLegacy($property, $type, $shortDescription, $longDescription); - } - - public static function provideLegacyCollectionTypes() - { - return [ - ['iteratorCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, [new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_INT)], new LegacyType(LegacyType::BUILTIN_TYPE_STRING))], null, null], - ['iteratorCollectionWithKey', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))], null, null], - [ - 'nestedIterators', - [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - 'Iterator', - true, - new LegacyType(LegacyType::BUILTIN_TYPE_INT), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING)) - )], - null, - null, - ], - [ - 'arrayWithKeys', - [new LegacyType( - LegacyType::BUILTIN_TYPE_ARRAY, - false, - null, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType(LegacyType::BUILTIN_TYPE_STRING) - )], - null, - null, - ], - [ - 'arrayWithKeysAndComplexValue', - [new LegacyType( - LegacyType::BUILTIN_TYPE_ARRAY, - false, - null, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType( - LegacyType::BUILTIN_TYPE_ARRAY, - true, - null, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_INT), - new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true) - ) - )], - null, - null, - ], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyTypesWithCustomPrefixes - */ - public function testExtractTypesWithCustomPrefixesLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $customExtractor = new PhpDocExtractor(null, ['add', 'remove'], ['is', 'can']); - - $this->assertEquals($type, $customExtractor->getTypes(Dummy::class, $property)); - } - - public static function provideLegacyTypesWithCustomPrefixes() - { - return [ - ['foo', null, 'Short description.', 'Long description.'], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], 'This is bar', null], - ['baz', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], 'Should be used.', null], - ['foo2', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)], null, null], - ['foo3', [new LegacyType(LegacyType::BUILTIN_TYPE_CALLABLE)], null, null], - ['foo4', [new LegacyType(LegacyType::BUILTIN_TYPE_NULL)], null, null], - ['foo5', null, null, null], - [ - 'files', - [ - new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), - new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE), - ], - null, - null, - ], - ['bal', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')], null, null], - ['parent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')], null, null], - ['collection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))], null, null], - ['nestedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)))], null, null], - ['mixedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, null, null)], null, null], - ['a', null, 'A.', null], - ['b', null, 'B.', null], - ['c', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL, true)], null, null], - ['d', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)], null, null], - ['e', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE))], null, null], - ['f', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))], null, null], - ['g', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)], 'Nullable array.', null], - ['h', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true)], null, null], - ['i', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true), new LegacyType(LegacyType::BUILTIN_TYPE_INT, true)], null, null], - ['j', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')], null, null], - ['nullableCollectionOfNonNullableElements', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_INT, false))], null, null], - ['nonNullableCollectionOfNullableElements', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_INT, true))], null, null], - ['nullableCollectionOfMultipleNonNullableElementTypes', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), [new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])], null, null], - ['donotexist', null, null, null], - ['staticGetter', null, null, null], - ['staticSetter', null, null, null], - ]; - } - - public static function provideLegacyTypesWithNoPrefixes() - { - return [ - ['foo', null, 'Short description.', 'Long description.'], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], 'This is bar', null], - ['baz', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], 'Should be used.', null], - ['foo2', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)], null, null], - ['foo3', [new LegacyType(LegacyType::BUILTIN_TYPE_CALLABLE)], null, null], - ['foo4', [new LegacyType(LegacyType::BUILTIN_TYPE_NULL)], null, null], - ['foo5', null, null, null], - [ - 'files', - [ - new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), - new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE), - ], - null, - null, - ], - ['bal', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')], null, null], - ['parent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')], null, null], - ['collection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))], null, null], - ['nestedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)))], null, null], - ['mixedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, null, null)], null, null], - ['a', null, 'A.', null], - ['b', null, 'B.', null], - ['c', null, null, null], - ['d', null, null, null], - ['e', null, null, null], - ['f', null, null, null], - ['g', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)], 'Nullable array.', null], - ['h', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true)], null, null], - ['i', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true), new LegacyType(LegacyType::BUILTIN_TYPE_INT, true)], null, null], - ['j', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')], null, null], - ['nullableCollectionOfNonNullableElements', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_INT, false))], null, null], - ['donotexist', null, null, null], - ['staticGetter', null, null, null], - ['staticSetter', null, null, null], - ]; - } - public function testReturnNullOnEmptyDocBlock() { $this->assertNull($this->extractor->getShortDescription(EmptyDocBlock::class, 'foo')); } - public static function provideLegacyDockBlockFallbackTypes() - { - return [ - 'pub' => [ - 'pub', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], - ], - 'protAcc' => [ - 'protAcc', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], - ], - 'protMut' => [ - 'protMut', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)], - ], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyDockBlockFallbackTypes - */ - public function testDocBlockFallbackLegacy($property, $types) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback', $property)); - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPropertiesDefinedByTraits - */ - public function testPropertiesDefinedByTraitsLegacy(string $property, LegacyType $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals([$type], $this->extractor->getTypes(DummyUsingTrait::class, $property)); - } - - public static function provideLegacyPropertiesDefinedByTraits(): array - { - return [ - ['propertyInTraitPrimitiveType', new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], - ['propertyInTraitObjectSameNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)], - ['propertyInTraitObjectDifferentNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], - ['propertyInExternalTraitPrimitiveType', new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], - ['propertyInExternalTraitObjectSameNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], - ['propertyInExternalTraitObjectDifferentNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyMethodsDefinedByTraits - */ - public function testMethodsDefinedByTraitsLegacy(string $property, LegacyType $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals([$type], $this->extractor->getTypes(DummyUsingTrait::class, $property)); - } - - public static function provideLegacyMethodsDefinedByTraits(): array - { - return [ - ['methodInTraitPrimitiveType', new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], - ['methodInTraitObjectSameNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)], - ['methodInTraitObjectDifferentNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], - ['methodInExternalTraitPrimitiveType', new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], - ['methodInExternalTraitObjectSameNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], - ['methodInExternalTraitObjectDifferentNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPropertiesStaticType - */ - public function testPropertiesStaticTypeLegacy(string $class, string $property, LegacyType $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals([$type], $this->extractor->getTypes($class, $property)); - } - - public static function provideLegacyPropertiesStaticType(): array - { - return [ - [ParentDummy::class, 'propertyTypeStatic', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)], - [Dummy::class, 'propertyTypeStatic', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPropertiesParentType - */ - public function testPropertiesParentTypeLegacy(string $class, string $property, ?array $types) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals($types, $this->extractor->getTypes($class, $property)); - } - - public static function provideLegacyPropertiesParentType(): array - { - return [ - [ParentDummy::class, 'parentAnnotationNoParent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'parent')]], - [Dummy::class, 'parentAnnotation', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]], - ]; - } - - /** - * @group legacy - */ - public function testUnknownPseudoTypeLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'scalar')], $this->extractor->getTypes(PseudoTypeDummy::class, 'unknownPseudoType')); - } - - /** - * @group legacy - */ - public function testGenericInterface() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertNull($this->extractor->getTypes(Dummy::class, 'genericInterface')); - } - - /** - * @group legacy - * - * @dataProvider provideLegacyConstructorTypes - */ - public function testExtractConstructorTypesLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypesFromConstructor()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypeFromConstructor()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypesFromConstructor('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property)); - } - - public static function provideLegacyConstructorTypes() - { - return [ - ['date', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['timezone', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]], - ['dateObject', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeInterface')]], - ['dateTime', null], - ['ddd', null], - ['mixed', null], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPseudoTypes - */ - public function testPseudoTypesLegacy($property, array $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\PseudoTypesDummy', $property)); - } - - public static function provideLegacyPseudoTypes(): array - { - return [ - ['classString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['classStringGeneric', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['htmlEscapedString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['lowercaseString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['nonEmptyLowercaseString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['nonEmptyString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['numericString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['traitString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['positiveInt', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false, null)]], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPromotedProperty - */ - public function testExtractPromotedPropertyLegacy(string $property, ?array $types) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor::getType()" instead.'); - - $this->assertEquals($types, $this->extractor->getTypes(Php80Dummy::class, $property)); - } - - public static function provideLegacyPromotedProperty(): array - { - return [ - ['promoted', null], - ['promotedAndMutated', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ]; - } - public function testParamTagTypeIsOmitted() { $this->assertNull($this->extractor->getType(OmittedParamTagTypeDocBlock::class, 'omittedType')); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php index a7d36203d49c6..d464b94c9a3f6 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\PropertyInfo\Tests\Extractor; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\Clazz; @@ -37,7 +36,6 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\AnotherNamespace\DummyInAnotherNamespace; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Exception\LogicException; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\WrappingTypeInterface; @@ -49,8 +47,6 @@ */ class PhpStanExtractorTest extends TestCase { - use ExpectUserDeprecationMessageTrait; - private PhpStanExtractor $extractor; private PhpDocExtractor $phpDocExtractor; @@ -60,618 +56,6 @@ protected function setUp(): void $this->phpDocExtractor = new PhpDocExtractor(); } - /** - * @group legacy - * - * @dataProvider provideLegacyTypes - */ - public function testExtractLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); - } - - /** - * @group legacy - */ - public function testParamTagTypeIsOmittedLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertNull($this->extractor->getTypes(PhpStanOmittedParamTagTypeDocBlock::class, 'omittedType')); - } - - public static function provideLegacyInvalidTypes() - { - return [ - 'pub' => ['pub'], - 'stat' => ['stat'], - 'foo' => ['foo'], - 'bar' => ['bar'], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyInvalidTypes - */ - public function testInvalidLegacy($property) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property)); - } - - /** - * @group legacy - * - * @dataProvider provideLegacyTypesWithNoPrefixes - */ - public function testExtractTypesWithNoPrefixesLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $noPrefixExtractor = new PhpStanExtractor([], [], []); - - $this->assertEquals($type, $noPrefixExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); - } - - public static function provideLegacyTypes() - { - return [ - ['foo', null], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ['baz', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['foo2', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]], - ['foo3', [new LegacyType(LegacyType::BUILTIN_TYPE_CALLABLE)]], - ['foo4', [new LegacyType(LegacyType::BUILTIN_TYPE_NULL)]], - ['foo5', null], - [ - 'files', - [ - new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), - new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE), - ], - ], - ['bal', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]], - ['parent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]], - ['collection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]], - ['nestedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)))]], - ['mixedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], null)]], - ['a', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['b', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]], - ['c', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL, true)]], - ['d', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]], - ['e', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE))]], - ['f', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]], - ['g', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)]], - ['h', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true)]], - ['j', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')]], - ['nullableCollectionOfNonNullableElements', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_INT, false))]], - ['donotexist', null], - ['staticGetter', null], - ['staticSetter', null], - ['emptyVar', null], - ['arrayWithKeys', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - ['arrayOfMixed', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_STRING), null)]], - ['listOfStrings', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - ['self', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)]], - ['rootDummyItems', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, RootDummyItem::class))]], - ['rootDummyItem', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, RootDummyItem::class)]], - ['collectionAsObject', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyCollection::class, true, [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])]], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyCollectionTypes - */ - public function testExtractCollectionLegacy($property, ?array $type = null) - { - $this->testExtractLegacy($property, $type); - } - - public static function provideLegacyCollectionTypes() - { - return [ - ['iteratorCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, null, new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - ['iteratorCollectionWithKey', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - [ - 'nestedIterators', - [new LegacyType( - LegacyType::BUILTIN_TYPE_OBJECT, - false, - 'Iterator', - true, - new LegacyType(LegacyType::BUILTIN_TYPE_INT), - new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING)) - )], - ], - [ - 'arrayWithKeys', - [new LegacyType( - LegacyType::BUILTIN_TYPE_ARRAY, - false, - null, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType(LegacyType::BUILTIN_TYPE_STRING) - )], - ], - [ - 'arrayWithKeysAndComplexValue', - [new LegacyType( - LegacyType::BUILTIN_TYPE_ARRAY, - false, - null, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_STRING), - new LegacyType( - LegacyType::BUILTIN_TYPE_ARRAY, - true, - null, - true, - new LegacyType(LegacyType::BUILTIN_TYPE_INT), - new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true) - ) - )], - ], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyTypesWithCustomPrefixes - */ - public function testExtractTypesWithCustomPrefixesLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $customExtractor = new PhpStanExtractor(['add', 'remove'], ['is', 'can']); - - $this->assertEquals($type, $customExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); - } - - public static function provideLegacyTypesWithCustomPrefixes() - { - return [ - ['foo', null], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ['baz', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['foo2', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]], - ['foo3', [new LegacyType(LegacyType::BUILTIN_TYPE_CALLABLE)]], - ['foo4', [new LegacyType(LegacyType::BUILTIN_TYPE_NULL)]], - ['foo5', null], - [ - 'files', - [ - new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), - new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE), - ], - ], - ['bal', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]], - ['parent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]], - ['collection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]], - ['nestedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)))]], - ['mixedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], null)]], - ['a', null], - ['b', null], - ['c', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL, true)]], - ['d', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]], - ['e', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE))]], - ['f', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]], - ['g', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)]], - ['h', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true)]], - ['j', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')]], - ['nullableCollectionOfNonNullableElements', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_INT, false))]], - ['donotexist', null], - ['staticGetter', null], - ['staticSetter', null], - ]; - } - - public static function provideLegacyTypesWithNoPrefixes() - { - return [ - ['foo', null], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ['baz', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['foo2', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]], - ['foo3', [new LegacyType(LegacyType::BUILTIN_TYPE_CALLABLE)]], - ['foo4', [new LegacyType(LegacyType::BUILTIN_TYPE_NULL)]], - ['foo5', null], - [ - 'files', - [ - new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), - new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE), - ], - ], - ['bal', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]], - ['parent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]], - ['collection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]], - ['nestedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)))]], - ['mixedCollection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], null)]], - ['a', null], - ['b', null], - ['c', null], - ['d', null], - ['e', null], - ['f', null], - ['g', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)]], - ['h', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, true)]], - ['j', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')]], - ['nullableCollectionOfNonNullableElements', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_INT, false))]], - ['donotexist', null], - ['staticGetter', null], - ['staticSetter', null], - ]; - } - - public static function provideLegacyDockBlockFallbackTypes() - { - return [ - 'pub' => [ - 'pub', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], - ], - 'protAcc' => [ - 'protAcc', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], - ], - 'protMut' => [ - 'protMut', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)], - ], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyDockBlockFallbackTypes - */ - public function testDocBlockFallbackLegacy($property, $types) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback', $property)); - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPropertiesDefinedByTraits - */ - public function testPropertiesDefinedByTraitsLegacy(string $property, LegacyType $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals([$type], $this->extractor->getTypes(DummyUsingTrait::class, $property)); - } - - public static function provideLegacyPropertiesDefinedByTraits(): array - { - return [ - ['propertyInTraitPrimitiveType', new LegacyType(LegacyType::BUILTIN_TYPE_STRING)], - ['propertyInTraitObjectSameNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)], - ['propertyInTraitObjectDifferentNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], - ['dummyInAnotherNamespace', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DummyInAnotherNamespace::class)], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPropertiesStaticType - */ - public function testPropertiesStaticTypeLegacy(string $class, string $property, LegacyType $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals([$type], $this->extractor->getTypes($class, $property)); - } - - public static function provideLegacyPropertiesStaticType(): array - { - return [ - [ParentDummy::class, 'propertyTypeStatic', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)], - [Dummy::class, 'propertyTypeStatic', new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPropertiesParentType - */ - public function testPropertiesParentTypeLegacy(string $class, string $property, ?array $types) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($types, $this->extractor->getTypes($class, $property)); - } - - public static function provideLegacyPropertiesParentType(): array - { - return [ - [ParentDummy::class, 'parentAnnotationNoParent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'parent')]], - [Dummy::class, 'parentAnnotation', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyConstructorTypes - */ - public function testExtractConstructorTypesLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypesFromConstructor()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypeFromConstructor()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypesFromConstructor('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property)); - } - - /** - * @group legacy - * - * @dataProvider provideLegacyConstructorTypes - */ - public function testExtractConstructorTypesReturnNullOnEmptyDocBlockLegacy($property) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypesFromConstructor()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypeFromConstructor()" instead.'); - - $this->assertNull($this->extractor->getTypesFromConstructor(ConstructorDummyWithoutDocBlock::class, $property)); - } - - public static function provideLegacyConstructorTypes() - { - return [ - ['date', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['timezone', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]], - ['dateObject', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeInterface')]], - ['dateTime', null], - ['ddd', null], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyUnionTypes - */ - public function testExtractorUnionTypesLegacy(string $property, ?array $types) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DummyUnionType', $property)); - } - - public static function provideLegacyUnionTypes(): array - { - return [ - ['a', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['b', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], [new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_INT)])]], - ['c', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [], [new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_INT)])]], - ['d', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_INT)], [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [], [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])])]], - ['e', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, Dummy::class, false, [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [], [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])], [new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [new LegacyType(LegacyType::BUILTIN_TYPE_INT)], [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, \Traversable::class, true, [], [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DefaultValue::class)])])]), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]], - ['f', null], - ['g', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, [], [new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_INT)])]], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPseudoTypes - */ - public function testPseudoTypesLegacy($property, array $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\PhpStanPseudoTypesDummy', $property)); - } - - public static function provideLegacyPseudoTypes(): array - { - return [ - ['classString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['classStringGeneric', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['htmlEscapedString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['lowercaseString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['nonEmptyLowercaseString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['nonEmptyString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['numericString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['traitString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['interfaceString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['literalString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false, null)]], - ['positiveInt', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false, null)]], - ['negativeInt', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false, null)]], - ['nonPositiveInt', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false, null)]], - ['nonNegativeInt', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false, null)]], - ['nonZeroInt', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false, null)]], - ['nonEmptyArray', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true)]], - ['nonEmptyList', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT))]], - ['scalar', [new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]], - ['number', [new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]], - ['numeric', [new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ['arrayKey', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING), new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['double', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]], - ]; - } - - /** - * @group legacy - */ - public function testDummyNamespaceLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals( - [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy')], - $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DummyNamespace', 'dummy') - ); - } - - /** - * @group legacy - */ - public function testDummyNamespaceWithPropertyLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $phpStanTypes = $this->extractor->getTypes(\B\Dummy::class, 'property'); - $phpDocTypes = $this->phpDocExtractor->getTypes(\B\Dummy::class, 'property'); - - $this->assertEquals('A\Property', $phpStanTypes[0]->getClassName()); - $this->assertEquals($phpDocTypes[0]->getClassName(), $phpStanTypes[0]->getClassName()); - } - - /** - * @group legacy - * - * @dataProvider provideLegacyIntRangeType - */ - public function testExtractorIntRangeTypeLegacy(string $property, ?array $types) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\IntRangeDummy', $property)); - } - - public static function provideLegacyIntRangeType(): array - { - return [ - ['a', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ['b', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, true)]], - ['c', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPhp80Types - */ - public function testExtractPhp80TypeLegacy(string $class, $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes($class, $property, [])); - } - - public static function provideLegacyPhp80Types() - { - return [ - [Php80Dummy::class, 'promotedWithDocCommentAndType', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - [Php80Dummy::class, 'promotedWithDocComment', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - [Php80Dummy::class, 'promotedAndMutated', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - [Php80Dummy::class, 'promoted', null], - [Php80Dummy::class, 'collection', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, collection: true, collectionValueType: new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - [Php80PromotedDummy::class, 'promoted', null], - ]; - } - - /** - * @group legacy - * - * @dataProvider allowPrivateAccessLegacyProvider - */ - public function testAllowPrivateAccessLegacy(bool $allowPrivateAccess, array $expectedTypes) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $extractor = new PhpStanExtractor(allowPrivateAccess: $allowPrivateAccess); - $this->assertEquals( - $expectedTypes, - $extractor->getTypes(DummyPropertyAndGetterWithDifferentTypes::class, 'foo') - ); - } - - public static function allowPrivateAccessLegacyProvider(): array - { - return [ - [true, [new LegacyType('string')]], - [false, [new LegacyType('array', collection: true, collectionKeyType: new LegacyType('int'), collectionValueType: new LegacyType('string'))]], - ]; - } - - /** - * @group legacy - * - * @param list $expectedTypes - * - * @dataProvider legacyGenericsProvider - */ - public function testGenericsLegacy(string $property, array $expectedTypes) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor::getType()" instead.'); - - $this->assertEquals($expectedTypes, $this->extractor->getTypes(DummyGeneric::class, $property)); - } - - /** - * @return iterable}> - */ - public static function legacyGenericsProvider(): iterable - { - yield [ - 'basicClass', - [ - new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: Clazz::class, - collectionValueType: new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: Dummy::class, - ) - ), - ], - ]; - yield [ - 'nullableClass', - [ - new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: Clazz::class, - nullable: true, - collectionValueType: new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: Dummy::class, - ) - ), - ], - ]; - yield [ - 'basicInterface', - [ - new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: IFace::class, - collectionValueType: new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: Dummy::class, - ) - ), - ], - ]; - yield [ - 'nullableInterface', - [ - new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: IFace::class, - nullable: true, - collectionValueType: new LegacyType( - builtinType: LegacyType::BUILTIN_TYPE_OBJECT, - class: Dummy::class, - ) - ), - ], - ]; - } - /** * @dataProvider typesProvider */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 330a35db87746..6c9eac395766e 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\PropertyInfo\Tests\Extractor; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\PropertyReadInfo; use Symfony\Component\PropertyInfo\PropertyWriteInfo; @@ -34,7 +33,6 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\Php82Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\SnakeCaseDummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\VirtualProperties; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\NullableType; @@ -43,8 +41,6 @@ */ class ReflectionExtractorTest extends TestCase { - use ExpectUserDeprecationMessageTrait; - private ReflectionExtractor $extractor; protected function setUp(): void @@ -223,182 +219,11 @@ public function testGetPropertiesWithNoPrefixes() ); } - /** - * @group legacy - * - * @dataProvider provideLegacyTypes - */ - public function testExtractorsLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property, [])); - } - - public static function provideLegacyTypes() - { - return [ - ['a', null], - ['b', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]], - ['c', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]], - ['d', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]], - ['e', null], - ['f', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable'))]], - ['donotexist', null], - ['staticGetter', null], - ['staticSetter', null], - ['self', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy')]], - ['realParent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')]], - ['date', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, \DateTimeImmutable::class)]], - ['dates', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, \DateTimeImmutable::class))]], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPhp7Types - */ - public function testExtractPhp7TypeLegacy(string $class, string $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes($class, $property, [])); - } - - public static function provideLegacyPhp7Types() - { - return [ - [Php7Dummy::class, 'foo', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true)]], - [Php7Dummy::class, 'bar', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]], - [Php7Dummy::class, 'baz', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - [Php7Dummy::class, 'buz', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\Php7Dummy')]], - [Php7Dummy::class, 'biz', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Php7ParentDummy::class)]], - [Php7Dummy::class, 'donotexist', null], - [Php7ParentDummy::class, 'parent', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, \stdClass::class)]], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPhp71Types - */ - public function testExtractPhp71TypeLegacy($property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy', $property, [])); - } - - public static function provideLegacyPhp71Types() - { - return [ - ['foo', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)]], - ['buz', [new LegacyType(LegacyType::BUILTIN_TYPE_NULL)]], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, true)]], - ['baz', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]], - ['donotexist', null], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPhp80Types - */ - public function testExtractPhp80TypeLegacy(string $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php80Dummy', $property, [])); - } - - public static function provideLegacyPhp80Types() - { - return [ - ['foo', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true)]], - ['bar', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, true)]], - ['timeout', [new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]], - ['optional', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, true), new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT, true)]], - ['string', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Stringable'), new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]], - ['payload', null], - ['data', null], - ['mixedProperty', null], - ]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyPhp81Types - */ - public function testExtractPhp81TypeLegacy(string $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php81Dummy', $property, [])); - } - - public static function provideLegacyPhp81Types() - { - return [ - ['nothing', null], - ['collection', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Traversable'), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Countable')]], - ]; - } - public function testReadonlyPropertiesAreNotWriteable() { $this->assertFalse($this->extractor->isWritable(Php81Dummy::class, 'foo')); } - /** - * @group legacy - * - * @dataProvider provideLegacyPhp82Types - */ - public function testExtractPhp82TypeLegacy(string $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php82Dummy', $property, [])); - } - - public static function provideLegacyPhp82Types(): iterable - { - yield ['nil', null]; - yield ['false', [new LegacyType(LegacyType::BUILTIN_TYPE_FALSE)]]; - yield ['true', [new LegacyType(LegacyType::BUILTIN_TYPE_TRUE)]]; - - // Nesting intersection and union types is not supported yet, - // but we should make sure this kind of composite types does not crash the extractor. - yield ['someCollection', null]; - } - - /** - * @group legacy - * - * @dataProvider provideLegacyDefaultValue - */ - public function testExtractWithDefaultValueLegacy($property, $type) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypes(DefaultValue::class, $property, [])); - } - - public static function provideLegacyDefaultValue() - { - return [ - ['defaultInt', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false)]], - ['defaultFloat', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT, false)]], - ['defaultString', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)]], - ['defaultArray', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true)]], - ['defaultNull', null], - ]; - } - /** * @dataProvider getReadableProperties */ @@ -521,35 +346,6 @@ public static function getInitializableProperties(): array ]; } - /** - * @group legacy - * - * @dataProvider provideLegacyConstructorTypes - */ - public function testExtractTypeConstructorLegacy(string $class, string $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - /* Check that constructor extractions works by default, and if passed in via context. - Check that null is returned if constructor extraction is disabled */ - $this->assertEquals($type, $this->extractor->getTypes($class, $property, [])); - $this->assertEquals($type, $this->extractor->getTypes($class, $property, ['enable_constructor_extraction' => true])); - $this->assertNull($this->extractor->getTypes($class, $property, ['enable_constructor_extraction' => false])); - } - - public static function provideLegacyConstructorTypes(): array - { - return [ - // php71 dummy has following constructor: __construct(string $string, int $intPrivate) - [Php71Dummy::class, 'string', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING, false)]], - [Php71Dummy::class, 'intPrivate', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false)]], - // Php71DummyExtended2 adds int $intWithAccessor - [Php71DummyExtended2::class, 'intWithAccessor', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false)]], - [Php71DummyExtended2::class, 'intPrivate', [new LegacyType(LegacyType::BUILTIN_TYPE_INT, false)]], - [DefaultValue::class, 'foo', null], - ]; - } - public function testNullOnPrivateProtectedAccessor() { $barAccessor = $this->extractor->getReadInfo(Dummy::class, 'bar'); @@ -563,21 +359,6 @@ public function testNullOnPrivateProtectedAccessor() $this->assertEquals(PropertyWriteInfo::TYPE_NONE, $bazMutator->getType()); } - /** - * @group legacy - */ - public function testTypedPropertiesLegacy() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getType()" instead.'); - - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class)], $this->extractor->getTypes(Php74Dummy::class, 'dummy')); - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_BOOL, true)], $this->extractor->getTypes(Php74Dummy::class, 'nullableBoolProp')); - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))], $this->extractor->getTypes(Php74Dummy::class, 'stringCollection')); - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_INT, true)], $this->extractor->getTypes(Php74Dummy::class, 'nullableWithDefault')); - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true)], $this->extractor->getTypes(Php74Dummy::class, 'collection')); - $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, true, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Dummy::class))], $this->extractor->getTypes(Php74Dummy::class, 'nullableTypedCollection')); - } - /** * @dataProvider readAccessorProvider */ @@ -701,29 +482,6 @@ public function testGetWriteInfoReadonlyProperties() $this->assertSame(PropertyWriteInfo::TYPE_NONE, $writeMutatorWithoutConstructor->getType()); } - /** - * @group legacy - * - * @dataProvider provideLegacyExtractConstructorTypes - */ - public function testExtractConstructorTypesLegacy(string $property, ?array $type = null) - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypesFromConstructor()" method is deprecated, use "Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypeFromConstructor()" instead.'); - - $this->assertEquals($type, $this->extractor->getTypesFromConstructor('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property)); - } - - public static function provideLegacyExtractConstructorTypes(): array - { - return [ - ['timezone', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]], - ['date', null], - ['dateObject', null], - ['dateTime', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]], - ['ddd', null], - ]; - } - public function testAsymmetricVisibility() { $this->assertTrue($this->extractor->isReadable(AsymmetricVisibility::class, 'publicPrivate')); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php index cfffd45e0c05f..1d02be96478c7 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php @@ -17,7 +17,6 @@ use Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; /** @@ -35,21 +34,11 @@ public function getLongDescription($class, $property, array $context = []): ?str return 'long'; } - public function getTypes($class, $property, array $context = []): ?array - { - return [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]; - } - public function getType($class, $property, array $context = []): ?Type { return Type::int(); } - public function getTypesFromConstructor(string $class, string $property): ?array - { - return [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]; - } - public function getTypeFromConstructor(string $class, string $property): ?Type { return Type::string(); diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php index fda169d3efc93..f721f3a59f1d1 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoCacheExtractorTest.php @@ -11,23 +11,14 @@ namespace Symfony\Component\PropertyInfo\Tests; -use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor; -use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; -use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; -use Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy; -use Symfony\Component\TypeInfo\Type; /** * @author Kévin Dunglas */ class PropertyInfoCacheExtractorTest extends AbstractPropertyInfoExtractorTest { - use ExpectUserDeprecationMessageTrait; - protected function setUp(): void { parent::setUp(); @@ -53,17 +44,6 @@ public function testGetType() parent::testGetType(); } - /** - * @group legacy - */ - public function testGetTypes() - { - $this->expectUserDeprecationMessage('Since symfony/property-info 7.3: The "Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor::getTypes()" method is deprecated, use "Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor::getType()" instead.'); - - parent::testGetTypes(); - parent::testGetTypes(); - } - public function testIsReadable() { parent::testIsReadable(); @@ -87,90 +67,4 @@ public function testIsInitializable() parent::testIsInitializable(); parent::testIsInitializable(); } - - /** - * @group legacy - * - * @dataProvider provideNestedExtractorWithoutGetTypeImplementationData - */ - public function testNestedExtractorWithoutGetTypeImplementation(string $property, ?Type $expectedType) - { - $propertyInfoCacheExtractor = new PropertyInfoCacheExtractor(new class implements PropertyInfoExtractorInterface { - private PropertyTypeExtractorInterface $propertyTypeExtractor; - - public function __construct() - { - $this->propertyTypeExtractor = new PhpDocExtractor(); - } - - public function getTypes(string $class, string $property, array $context = []): ?array - { - return $this->propertyTypeExtractor->getTypes($class, $property, $context); - } - - public function isReadable(string $class, string $property, array $context = []): ?bool - { - return null; - } - - public function isWritable(string $class, string $property, array $context = []): ?bool - { - return null; - } - - public function getShortDescription(string $class, string $property, array $context = []): ?string - { - return null; - } - - public function getLongDescription(string $class, string $property, array $context = []): ?string - { - return null; - } - - public function getProperties(string $class, array $context = []): ?array - { - return null; - } - }, new ArrayAdapter()); - - if (null === $expectedType) { - $this->assertNull($propertyInfoCacheExtractor->getType(Dummy::class, $property)); - } else { - $this->assertEquals($expectedType, $propertyInfoCacheExtractor->getType(Dummy::class, $property)); - } - } - - public static function provideNestedExtractorWithoutGetTypeImplementationData() - { - yield ['bar', Type::string()]; - yield ['baz', Type::int()]; - yield ['bal', Type::object(\DateTimeImmutable::class)]; - yield ['parent', Type::object(ParentDummy::class)]; - yield ['collection', Type::array(Type::object(\DateTimeImmutable::class), Type::int())]; - yield ['nestedCollection', Type::array(Type::array(Type::string(), Type::int()), Type::int())]; - yield ['mixedCollection', Type::array()]; - yield ['B', Type::object(ParentDummy::class)]; - yield ['Id', Type::int()]; - yield ['Guid', Type::string()]; - yield ['g', Type::nullable(Type::array())]; - yield ['h', Type::nullable(Type::string())]; - yield ['i', Type::nullable(Type::union(Type::string(), Type::int()))]; - yield ['j', Type::nullable(Type::object(\DateTimeImmutable::class))]; - yield ['nullableCollectionOfNonNullableElements', Type::nullable(Type::array(Type::int(), Type::int()))]; - yield ['nonNullableCollectionOfNullableElements', Type::array(Type::nullable(Type::int()), Type::int())]; - yield ['nullableCollectionOfMultipleNonNullableElementTypes', Type::nullable(Type::array(Type::union(Type::int(), Type::string()), Type::int()))]; - yield ['xTotals', Type::array()]; - yield ['YT', Type::string()]; - yield ['emptyVar', null]; - yield ['iteratorCollection', Type::collection(Type::object(\Iterator::class), Type::string(), Type::union(Type::string(), Type::int()))]; - yield ['iteratorCollectionWithKey', Type::collection(Type::object(\Iterator::class), Type::string(), Type::int())]; - yield ['nestedIterators', Type::collection(Type::object(\Iterator::class), Type::collection(Type::object(\Iterator::class), Type::string(), Type::int()), Type::int())]; - yield ['arrayWithKeys', Type::array(Type::string(), Type::string())]; - yield ['arrayWithKeysAndComplexValue', Type::array(Type::nullable(Type::array(Type::nullable(Type::string()), Type::int())), Type::string())]; - yield ['arrayOfMixed', Type::array(Type::mixed(), Type::string())]; - yield ['noDocBlock', null]; - yield ['listOfStrings', Type::array(Type::string(), Type::int())]; - yield ['parentAnnotation', Type::object(ParentDummy::class)]; - } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php deleted file mode 100644 index 33e80626f7438..0000000000000 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php +++ /dev/null @@ -1,86 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\PropertyInfo\Tests; - -use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; -use Symfony\Component\PropertyInfo\PropertyInfoExtractor; -use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; -use Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy; -use Symfony\Component\TypeInfo\Type; - -/** - * @author Kévin Dunglas - */ -class PropertyInfoExtractorTest extends AbstractPropertyInfoExtractorTest -{ - /** - * @group legacy - * - * @dataProvider provideNestedExtractorWithoutGetTypeImplementationData - */ - public function testNestedExtractorWithoutGetTypeImplementation(string $property, ?Type $expectedType) - { - $propertyInfoExtractor = new PropertyInfoExtractor([], [new class implements PropertyTypeExtractorInterface { - private PropertyTypeExtractorInterface $propertyTypeExtractor; - - public function __construct() - { - $this->propertyTypeExtractor = new PhpDocExtractor(); - } - - public function getTypes(string $class, string $property, array $context = []): ?array - { - return $this->propertyTypeExtractor->getTypes($class, $property, $context); - } - }]); - - if (null === $expectedType) { - $this->assertNull($propertyInfoExtractor->getType(Dummy::class, $property)); - } else { - $this->assertEquals($expectedType, $propertyInfoExtractor->getType(Dummy::class, $property)); - } - } - - public static function provideNestedExtractorWithoutGetTypeImplementationData() - { - yield ['bar', Type::string()]; - yield ['baz', Type::int()]; - yield ['bal', Type::object(\DateTimeImmutable::class)]; - yield ['parent', Type::object(ParentDummy::class)]; - yield ['collection', Type::array(Type::object(\DateTimeImmutable::class), Type::int())]; - yield ['nestedCollection', Type::array(Type::array(Type::string(), Type::int()), Type::int())]; - yield ['mixedCollection', Type::array()]; - yield ['B', Type::object(ParentDummy::class)]; - yield ['Id', Type::int()]; - yield ['Guid', Type::string()]; - yield ['g', Type::nullable(Type::array())]; - yield ['h', Type::nullable(Type::string())]; - yield ['i', Type::nullable(Type::union(Type::string(), Type::int()))]; - yield ['j', Type::nullable(Type::object(\DateTimeImmutable::class))]; - yield ['nullableCollectionOfNonNullableElements', Type::nullable(Type::array(Type::int(), Type::int()))]; - yield ['nonNullableCollectionOfNullableElements', Type::array(Type::nullable(Type::int()), Type::int())]; - yield ['nullableCollectionOfMultipleNonNullableElementTypes', Type::nullable(Type::array(Type::union(Type::int(), Type::string()), Type::int()))]; - yield ['xTotals', Type::array()]; - yield ['YT', Type::string()]; - yield ['emptyVar', null]; - yield ['iteratorCollection', Type::collection(Type::object(\Iterator::class), Type::string(), Type::union(Type::string(), Type::int()))]; - yield ['iteratorCollectionWithKey', Type::collection(Type::object(\Iterator::class), Type::string(), Type::int())]; - yield ['nestedIterators', Type::collection(Type::object(\Iterator::class), Type::collection(Type::object(\Iterator::class), Type::string(), Type::int()), Type::int())]; - yield ['arrayWithKeys', Type::array(Type::string(), Type::string())]; - yield ['arrayWithKeysAndComplexValue', Type::array(Type::nullable(Type::array(Type::nullable(Type::string()), Type::int())), Type::string())]; - yield ['arrayOfMixed', Type::array(Type::mixed(), Type::string())]; - yield ['noDocBlock', null]; - yield ['listOfStrings', Type::array(Type::string(), Type::int())]; - yield ['parentAnnotation', Type::object(ParentDummy::class)]; - } -} diff --git a/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php b/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php deleted file mode 100644 index afe4bb55f06ae..0000000000000 --- a/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php +++ /dev/null @@ -1,90 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\PropertyInfo\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\PropertyInfo\Type; - -/** - * @author Kévin Dunglas - * - * @group legacy - */ -class TypeTest extends TestCase -{ - public function testConstruct() - { - $type = new Type('object', true, 'ArrayObject', true, new Type('int'), new Type('string')); - - $this->assertEquals(Type::BUILTIN_TYPE_OBJECT, $type->getBuiltinType()); - $this->assertTrue($type->isNullable()); - $this->assertEquals('ArrayObject', $type->getClassName()); - $this->assertTrue($type->isCollection()); - - $collectionKeyTypes = $type->getCollectionKeyTypes(); - $this->assertIsArray($collectionKeyTypes); - $this->assertContainsOnlyInstancesOf('Symfony\Component\PropertyInfo\Type', $collectionKeyTypes); - $this->assertEquals(Type::BUILTIN_TYPE_INT, $collectionKeyTypes[0]->getBuiltinType()); - - $collectionValueTypes = $type->getCollectionValueTypes(); - $this->assertIsArray($collectionValueTypes); - $this->assertContainsOnlyInstancesOf('Symfony\Component\PropertyInfo\Type', $collectionValueTypes); - $this->assertEquals(Type::BUILTIN_TYPE_STRING, $collectionValueTypes[0]->getBuiltinType()); - } - - public function testIterable() - { - $type = new Type('iterable'); - $this->assertSame('iterable', $type->getBuiltinType()); - } - - public function testInvalidType() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('"foo" is not a valid PHP type.'); - new Type('foo'); - } - - public function testArrayCollection() - { - $type = new Type('array', false, null, true, [new Type('int'), new Type('string')], [new Type('object', false, \ArrayObject::class, true), new Type('array', false, null, true)]); - - $this->assertEquals(Type::BUILTIN_TYPE_ARRAY, $type->getBuiltinType()); - $this->assertFalse($type->isNullable()); - $this->assertTrue($type->isCollection()); - - [$firstKeyType, $secondKeyType] = $type->getCollectionKeyTypes(); - $this->assertEquals(Type::BUILTIN_TYPE_INT, $firstKeyType->getBuiltinType()); - $this->assertFalse($firstKeyType->isNullable()); - $this->assertFalse($firstKeyType->isCollection()); - $this->assertEquals(Type::BUILTIN_TYPE_STRING, $secondKeyType->getBuiltinType()); - $this->assertFalse($secondKeyType->isNullable()); - $this->assertFalse($secondKeyType->isCollection()); - - [$firstValueType, $secondValueType] = $type->getCollectionValueTypes(); - $this->assertEquals(Type::BUILTIN_TYPE_OBJECT, $firstValueType->getBuiltinType()); - $this->assertEquals(\ArrayObject::class, $firstValueType->getClassName()); - $this->assertFalse($firstValueType->isNullable()); - $this->assertTrue($firstValueType->isCollection()); - $this->assertEquals(Type::BUILTIN_TYPE_ARRAY, $secondValueType->getBuiltinType()); - $this->assertFalse($secondValueType->isNullable()); - $this->assertTrue($secondValueType->isCollection()); - } - - public function testInvalidCollectionValueArgument() - { - $this->expectException(\TypeError::class); - $this->expectExceptionMessage('"Symfony\Component\PropertyInfo\Type::validateCollectionArgument()": Argument #5 ($collectionKeyType) must be of type "Symfony\Component\PropertyInfo\Type[]", "Symfony\Component\PropertyInfo\Type" or "null", array value "array" given.'); - - new Type('array', false, null, true, [new \stdClass()], [new Type('string')]); - } -} diff --git a/src/Symfony/Component/PropertyInfo/Type.php b/src/Symfony/Component/PropertyInfo/Type.php deleted file mode 100644 index 2bed492346370..0000000000000 --- a/src/Symfony/Component/PropertyInfo/Type.php +++ /dev/null @@ -1,167 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\PropertyInfo; - -trigger_deprecation('symfony/property-info', '7.3', 'The "%s" class is deprecated. Use "%s" class from "symfony/type-info" instead.', Type::class, \Symfony\Component\TypeInfo\Type::class); - -/** - * Type value object (immutable). - * - * @author Kévin Dunglas - * - * @deprecated since Symfony 7.3, use "Symfony\Component\TypeInfo\Type" class from "symfony/type-info" instead - * - * @final - */ -class Type -{ - public const BUILTIN_TYPE_INT = 'int'; - public const BUILTIN_TYPE_FLOAT = 'float'; - public const BUILTIN_TYPE_STRING = 'string'; - public const BUILTIN_TYPE_BOOL = 'bool'; - public const BUILTIN_TYPE_RESOURCE = 'resource'; - public const BUILTIN_TYPE_OBJECT = 'object'; - public const BUILTIN_TYPE_ARRAY = 'array'; - public const BUILTIN_TYPE_NULL = 'null'; - public const BUILTIN_TYPE_FALSE = 'false'; - public const BUILTIN_TYPE_TRUE = 'true'; - public const BUILTIN_TYPE_CALLABLE = 'callable'; - public const BUILTIN_TYPE_ITERABLE = 'iterable'; - - /** - * List of PHP builtin types. - * - * @var string[] - */ - public static array $builtinTypes = [ - self::BUILTIN_TYPE_INT, - self::BUILTIN_TYPE_FLOAT, - self::BUILTIN_TYPE_STRING, - self::BUILTIN_TYPE_BOOL, - self::BUILTIN_TYPE_RESOURCE, - self::BUILTIN_TYPE_OBJECT, - self::BUILTIN_TYPE_ARRAY, - self::BUILTIN_TYPE_CALLABLE, - self::BUILTIN_TYPE_FALSE, - self::BUILTIN_TYPE_TRUE, - self::BUILTIN_TYPE_NULL, - self::BUILTIN_TYPE_ITERABLE, - ]; - - /** - * List of PHP builtin collection types. - * - * @var string[] - */ - public static array $builtinCollectionTypes = [ - self::BUILTIN_TYPE_ARRAY, - self::BUILTIN_TYPE_ITERABLE, - ]; - - private array $collectionKeyType; - private array $collectionValueType; - - /** - * @param Type[]|Type|null $collectionKeyType - * @param Type[]|Type|null $collectionValueType - * - * @throws \InvalidArgumentException - */ - public function __construct( - private string $builtinType, - private bool $nullable = false, - private ?string $class = null, - private bool $collection = false, - array|self|null $collectionKeyType = null, - array|self|null $collectionValueType = null, - ) { - if (!\in_array($builtinType, self::$builtinTypes, true)) { - throw new \InvalidArgumentException(\sprintf('"%s" is not a valid PHP type.', $builtinType)); - } - - $this->collectionKeyType = $this->validateCollectionArgument($collectionKeyType, 5, '$collectionKeyType') ?? []; - $this->collectionValueType = $this->validateCollectionArgument($collectionValueType, 6, '$collectionValueType') ?? []; - } - - private function validateCollectionArgument(array|self|null $collectionArgument, int $argumentIndex, string $argumentName): ?array - { - if (null === $collectionArgument) { - return null; - } - - if (\is_array($collectionArgument)) { - foreach ($collectionArgument as $type) { - if (!$type instanceof self) { - throw new \TypeError(\sprintf('"%s()": Argument #%d (%s) must be of type "%s[]", "%s" or "null", array value "%s" given.', __METHOD__, $argumentIndex, $argumentName, self::class, self::class, get_debug_type($collectionArgument))); - } - } - - return $collectionArgument; - } - - return [$collectionArgument]; - } - - /** - * Gets built-in type. - * - * Can be bool, int, float, string, array, object, resource, null, callback or iterable. - */ - public function getBuiltinType(): string - { - return $this->builtinType; - } - - public function isNullable(): bool - { - return $this->nullable; - } - - /** - * Gets the class name. - * - * Only applicable if the built-in type is object. - */ - public function getClassName(): ?string - { - return $this->class; - } - - public function isCollection(): bool - { - return $this->collection; - } - - /** - * Gets collection key types. - * - * Only applicable for a collection type. - * - * @return Type[] - */ - public function getCollectionKeyTypes(): array - { - return $this->collectionKeyType; - } - - /** - * Gets collection value types. - * - * Only applicable for a collection type. - * - * @return Type[] - */ - public function getCollectionValueTypes(): array - { - return $this->collectionValueType; - } -} diff --git a/src/Symfony/Component/PropertyInfo/Util/LegacyTypeConverter.php b/src/Symfony/Component/PropertyInfo/Util/LegacyTypeConverter.php deleted file mode 100644 index 24cae602aac5b..0000000000000 --- a/src/Symfony/Component/PropertyInfo/Util/LegacyTypeConverter.php +++ /dev/null @@ -1,94 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\PropertyInfo\Util; - -use Symfony\Component\PropertyInfo\Type as LegacyType; -use Symfony\Component\TypeInfo\Type; - -/** - * @internal - */ -class LegacyTypeConverter -{ - /** - * @param LegacyType[]|null $legacyTypes - */ - public static function toTypeInfoType(?array $legacyTypes): ?Type - { - if (null === $legacyTypes || [] === $legacyTypes) { - return null; - } - - $nullable = false; - $types = []; - - foreach ($legacyTypes as $legacyType) { - switch ($legacyType->getBuiltinType()) { - case LegacyType::BUILTIN_TYPE_ARRAY: - $typeInfoType = Type::array(self::toTypeInfoType($legacyType->getCollectionValueTypes()), self::toTypeInfoType($legacyType->getCollectionKeyTypes())); - break; - case LegacyType::BUILTIN_TYPE_BOOL: - $typeInfoType = Type::bool(); - break; - case LegacyType::BUILTIN_TYPE_CALLABLE: - $typeInfoType = Type::callable(); - break; - case LegacyType::BUILTIN_TYPE_FALSE: - $typeInfoType = Type::false(); - break; - case LegacyType::BUILTIN_TYPE_FLOAT: - $typeInfoType = Type::float(); - break; - case LegacyType::BUILTIN_TYPE_INT: - $typeInfoType = Type::int(); - break; - case LegacyType::BUILTIN_TYPE_ITERABLE: - $typeInfoType = Type::iterable(self::toTypeInfoType($legacyType->getCollectionValueTypes()), self::toTypeInfoType($legacyType->getCollectionKeyTypes())); - break; - case LegacyType::BUILTIN_TYPE_OBJECT: - if ($legacyType->isCollection()) { - $typeInfoType = Type::collection(Type::object($legacyType->getClassName()), self::toTypeInfoType($legacyType->getCollectionValueTypes()), self::toTypeInfoType($legacyType->getCollectionKeyTypes())); - } else { - $typeInfoType = Type::object($legacyType->getClassName()); - } - - break; - case LegacyType::BUILTIN_TYPE_RESOURCE: - $typeInfoType = Type::resource(); - break; - case LegacyType::BUILTIN_TYPE_STRING: - $typeInfoType = Type::string(); - break; - case LegacyType::BUILTIN_TYPE_TRUE: - $typeInfoType = Type::true(); - break; - default: - $typeInfoType = null; - break; - } - - if (LegacyType::BUILTIN_TYPE_NULL === $legacyType->getBuiltinType() || $legacyType->isNullable()) { - $nullable = true; - } - - if (null !== $typeInfoType) { - $types[] = $typeInfoType; - } - } - - if (1 === \count($types)) { - return $nullable ? Type::nullable($types[0]) : $types[0]; - } - - return $nullable ? Type::nullable(Type::union(...$types)) : Type::union(...$types); - } -} diff --git a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php index 4537ab6799574..b33ec1dafd0f7 100644 --- a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php +++ b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php @@ -22,7 +22,6 @@ use phpDocumentor\Reflection\Types\Null_; use phpDocumentor\Reflection\Types\Nullable; use phpDocumentor\Reflection\Types\String_; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeIdentifier; @@ -38,76 +37,6 @@ class_exists(List_::class); */ final class PhpDocTypeHelper { - /** - * Creates a {@see LegacyType} from a PHPDoc type. - * - * @deprecated since Symfony 7.3, use "getType" instead - * - * @return LegacyType[] - */ - public function getTypes(DocType $varType): array - { - trigger_deprecation('symfony/property-info', '7.3', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class); - - if ($varType instanceof ConstExpression) { - // It's safer to fall back to other extractors here, as resolving const types correctly is not easy at the moment - return []; - } - - $types = []; - $nullable = false; - - if ($varType instanceof Nullable) { - $nullable = true; - $varType = $varType->getActualType(); - } - - if (!$varType instanceof Compound) { - if ($varType instanceof Null_) { - $nullable = true; - } - - $type = $this->createLegacyType($varType, $nullable); - if (null !== $type) { - $types[] = $type; - } - - return $types; - } - - $varTypes = []; - for ($typeIndex = 0; $varType->has($typeIndex); ++$typeIndex) { - $type = $varType->get($typeIndex); - - if ($type instanceof ConstExpression) { - // It's safer to fall back to other extractors here, as resolving const types correctly is not easy at the moment - return []; - } - - // If null is present, all types are nullable - if ($type instanceof Null_) { - $nullable = true; - continue; - } - - if ($type instanceof Nullable) { - $nullable = true; - $type = $type->getActualType(); - } - - $varTypes[] = $type; - } - - foreach ($varTypes as $varType) { - $type = $this->createLegacyType($varType, $nullable); - if (null !== $type) { - $types[] = $type; - } - } - - return $types; - } - /** * Creates a {@see Type} from a PHPDoc type. */ @@ -170,74 +99,6 @@ public function getType(DocType $varType): ?Type return $nullable ? Type::nullable($type) : $type; } - /** - * Creates a {@see LegacyType} from a PHPDoc type. - */ - private function createLegacyType(DocType $type, bool $nullable): ?LegacyType - { - $docType = (string) $type; - - if ($type instanceof Collection) { - $fqsen = $type->getFqsen(); - if ($fqsen && 'list' === $fqsen->getName() && !class_exists(List_::class, false) && !class_exists((string) $fqsen)) { - // Workaround for phpdocumentor/type-resolver < 1.6 - return new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), $this->getTypes($type->getValueType())); - } - - [$phpType, $class] = $this->getPhpTypeAndClass((string) $fqsen); - - $collection = is_a($class, \Traversable::class, true) || is_a($class, \ArrayAccess::class, true); - - // it's safer to fall back to other extractors if the generic type is too abstract - if (!$collection && !class_exists($class)) { - return null; - } - - $keys = $this->getTypes($type->getKeyType()); - $values = $this->getTypes($type->getValueType()); - - return new LegacyType($phpType, $nullable, $class, $collection, $keys, $values); - } - - // Cannot guess - if (!$docType || 'mixed' === $docType) { - return null; - } - - if (str_ends_with($docType, '[]') && $type instanceof Array_) { - $collectionKeyTypes = new LegacyType(LegacyType::BUILTIN_TYPE_INT); - $collectionValueTypes = $this->getTypes($type->getValueType()); - - return new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyTypes, $collectionValueTypes); - } - - if ((str_starts_with($docType, 'list<') || str_starts_with($docType, 'array<')) && $type instanceof Array_) { - // array is converted to x[] which is handled above - // so it's only necessary to handle array here - $collectionKeyTypes = $this->getTypes($type->getKeyType()); - $collectionValueTypes = $this->getTypes($type->getValueType()); - - return new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyTypes, $collectionValueTypes); - } - - if ($type instanceof PseudoType) { - if ($type->underlyingType() instanceof Integer) { - return new LegacyType(LegacyType::BUILTIN_TYPE_INT, $nullable, null); - } elseif ($type->underlyingType() instanceof String_) { - return new LegacyType(LegacyType::BUILTIN_TYPE_STRING, $nullable, null); - } - } - - $docType = $this->normalizeType($docType); - [$phpType, $class] = $this->getPhpTypeAndClass($docType); - - if ('array' === $docType) { - return new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, null, null); - } - - return new LegacyType($phpType, $nullable, $class); - } - /** * Creates a {@see Type} from a PHPDoc type. */ @@ -319,19 +180,6 @@ private function createType(DocType $docType): ?Type return null !== $class ? Type::object($class) : Type::builtin($phpType); } - private function normalizeType(string $docType): string - { - return match ($docType) { - 'integer' => 'int', - 'boolean' => 'bool', - // real is not part of the PHPDoc standard, so we ignore it - 'double' => 'float', - 'callback' => 'callable', - 'void' => 'null', - default => $docType, - }; - } - private function getPhpTypeAndClass(string $docType): array { if (\in_array($docType, TypeIdentifier::values(), true)) { diff --git a/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php b/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php deleted file mode 100644 index 89e40e59390c9..0000000000000 --- a/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php +++ /dev/null @@ -1,214 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\PropertyInfo\Util; - -use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; -use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode; -use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode; -use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; -use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; -use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; -use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode; -use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode; -use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; -use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; -use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; -use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode; -use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; -use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use Symfony\Component\PropertyInfo\Type; -use Symfony\Component\TypeInfo\TypeContext\TypeContext; - -/** - * Transforms a php doc tag value to a {@link Type} instance. - * - * @author Baptiste Leduc - * - * @internal - */ -final class PhpStanTypeHelper -{ - /** - * Creates a {@see Type} from a PhpDocTagValueNode type. - * - * @return Type[] - */ - public function getTypes(PhpDocTagValueNode $node, TypeContext $typeContext): array - { - if ($node instanceof ParamTagValueNode || $node instanceof ReturnTagValueNode || $node instanceof VarTagValueNode) { - return $this->compressNullableType($this->extractTypes($node->type, $typeContext)); - } - - return []; - } - - /** - * Because PhpStan extract null as a separated type when Symfony / PHP compress it in the first available type we - * need this method to mimic how Symfony want null types. - * - * @param Type[] $types - * - * @return Type[] - */ - private function compressNullableType(array $types): array - { - $firstTypeIndex = null; - $nullableTypeIndex = null; - - foreach ($types as $k => $type) { - if (null === $firstTypeIndex && Type::BUILTIN_TYPE_NULL !== $type->getBuiltinType() && !$type->isNullable()) { - $firstTypeIndex = $k; - } - - if (null === $nullableTypeIndex && Type::BUILTIN_TYPE_NULL === $type->getBuiltinType()) { - $nullableTypeIndex = $k; - } - - if (null !== $firstTypeIndex && null !== $nullableTypeIndex) { - break; - } - } - - if (null !== $firstTypeIndex && null !== $nullableTypeIndex) { - $firstType = $types[$firstTypeIndex]; - $types[$firstTypeIndex] = new Type( - $firstType->getBuiltinType(), - true, - $firstType->getClassName(), - $firstType->isCollection(), - $firstType->getCollectionKeyTypes(), - $firstType->getCollectionValueTypes() - ); - unset($types[$nullableTypeIndex]); - } - - return array_values($types); - } - - /** - * @return Type[] - */ - private function extractTypes(TypeNode $node, TypeContext $typeContext): array - { - if ($node instanceof UnionTypeNode) { - $types = []; - foreach ($node->types as $type) { - if ($type instanceof ConstTypeNode) { - // It's safer to fall back to other extractors here, as resolving const types correctly is not easy at the moment - return []; - } - foreach ($this->extractTypes($type, $typeContext) as $subType) { - $types[] = $subType; - } - } - - return $this->compressNullableType($types); - } - if ($node instanceof GenericTypeNode) { - if ('class-string' === $node->type->name) { - return [new Type(Type::BUILTIN_TYPE_STRING)]; - } - - [$mainType] = $this->extractTypes($node->type, $typeContext); - - if (Type::BUILTIN_TYPE_INT === $mainType->getBuiltinType()) { - return [$mainType]; - } - - $collection = $mainType->isCollection() || is_a($mainType->getClassName(), \Traversable::class, true) || is_a($mainType->getClassName(), \ArrayAccess::class, true); - - // it's safer to fall back to other extractors if the generic type is too abstract - if (!$collection && !class_exists($mainType->getClassName()) && !interface_exists($mainType->getClassName(), false)) { - return []; - } - - $collectionKeyTypes = $mainType->getCollectionKeyTypes(); - $collectionKeyValues = []; - if (1 === \count($node->genericTypes)) { - foreach ($this->extractTypes($node->genericTypes[0], $typeContext) as $subType) { - $collectionKeyValues[] = $subType; - } - } elseif (2 === \count($node->genericTypes)) { - foreach ($this->extractTypes($node->genericTypes[0], $typeContext) as $keySubType) { - $collectionKeyTypes[] = $keySubType; - } - foreach ($this->extractTypes($node->genericTypes[1], $typeContext) as $valueSubType) { - $collectionKeyValues[] = $valueSubType; - } - } - - return [new Type($mainType->getBuiltinType(), $mainType->isNullable(), $mainType->getClassName(), $collection, $collectionKeyTypes, $collectionKeyValues)]; - } - if ($node instanceof ArrayShapeNode) { - return [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)]; - } - if ($node instanceof ArrayTypeNode) { - return [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], $this->extractTypes($node->type, $typeContext))]; - } - if ($node instanceof CallableTypeNode || $node instanceof CallableTypeParameterNode) { - return [new Type(Type::BUILTIN_TYPE_CALLABLE)]; - } - if ($node instanceof NullableTypeNode) { - $subTypes = $this->extractTypes($node->type, $typeContext); - if (\count($subTypes) > 1) { - $subTypes[] = new Type(Type::BUILTIN_TYPE_NULL); - - return $subTypes; - } - - return [new Type($subTypes[0]->getBuiltinType(), true, $subTypes[0]->getClassName(), $subTypes[0]->isCollection(), $subTypes[0]->getCollectionKeyTypes(), $subTypes[0]->getCollectionValueTypes())]; - } - if ($node instanceof ThisTypeNode) { - return [new Type(Type::BUILTIN_TYPE_OBJECT, false, $typeContext->getCalledClass())]; - } - if ($node instanceof IdentifierTypeNode) { - if (\in_array($node->name, Type::$builtinTypes, true)) { - return [new Type($node->name, false, null, \in_array($node->name, Type::$builtinCollectionTypes, true))]; - } - - return match ($node->name) { - 'integer', - 'positive-int', - 'negative-int', - 'non-positive-int', - 'non-negative-int', - 'non-zero-int' => [new Type(Type::BUILTIN_TYPE_INT)], - 'double' => [new Type(Type::BUILTIN_TYPE_FLOAT)], - 'list', - 'non-empty-list' => [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT))], - 'non-empty-array' => [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)], - 'mixed' => [], // mixed seems to be ignored in all other extractors - 'parent' => [new Type(Type::BUILTIN_TYPE_OBJECT, false, $node->name)], - 'static', - 'self' => [new Type(Type::BUILTIN_TYPE_OBJECT, false, $typeContext->getCalledClass())], - 'class-string', - 'html-escaped-string', - 'lowercase-string', - 'non-empty-lowercase-string', - 'non-empty-string', - 'numeric-string', - 'trait-string', - 'interface-string', - 'literal-string' => [new Type(Type::BUILTIN_TYPE_STRING)], - 'void' => [new Type(Type::BUILTIN_TYPE_NULL)], - 'scalar' => [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT), new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_BOOL)], - 'number' => [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT)], - 'numeric' => [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT), new Type(Type::BUILTIN_TYPE_STRING)], - 'array-key' => [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)], - default => [new Type(Type::BUILTIN_TYPE_OBJECT, false, $typeContext->normalize($node->name))], - }; - } - - return []; - } -} diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index d4daa76a6e72b..481fedf15cda9 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -24,7 +24,6 @@ ], "require": { "php": ">=8.4", - "symfony/deprecation-contracts": "^2.5|^3", "symfony/string": "^7.4|^8.0", "symfony/type-info": "^7.4|^8.0" }, diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index c346aafa8f450..7a13fbdc2bc9a 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -17,7 +17,6 @@ use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\Serializer\Encoder\CsvEncoder; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; @@ -120,7 +119,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer protected ?ClassDiscriminatorResolverInterface $classDiscriminatorResolver; /** - * @var array|false> + * @var array */ private array $typeCache = []; private array $attributesCache = []; @@ -307,7 +306,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a $this->validateCallbackContext($context); - if (null === $data && isset($context['value_type']) && ($context['value_type'] instanceof Type || $context['value_type'] instanceof LegacyType) && $context['value_type']->isNullable()) { + if (null === $data && isset($context['value_type']) && $context['value_type'] instanceof Type && $context['value_type']->isNullable()) { return null; } @@ -375,13 +374,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a if (null !== $type = $this->getType($resolvedClass, $attribute)) { try { - // BC layer for PropertyTypeExtractorInterface::getTypes(). - // Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - if (\is_array($type)) { - $value = $this->validateAndDenormalizeLegacy($type, $resolvedClass, $attribute, $value, $format, $attributeContext); - } else { - $value = $this->validateAndDenormalize($type, $resolvedClass, $attribute, $value, $format, $attributeContext); - } + $value = $this->validateAndDenormalize($type, $resolvedClass, $attribute, $value, $format, $attributeContext); } catch (NotNormalizableValueException $exception) { if (isset($context['not_normalizable_value_exceptions'])) { $context['not_normalizable_value_exceptions'][] = $exception; @@ -422,232 +415,6 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a abstract protected function setAttributeValue(object $object, string $attribute, mixed $value, ?string $format = null, array $context = []): void; - /** - * Validates the submitted data and denormalizes it. - * - * BC layer for PropertyTypeExtractorInterface::getTypes(). - * Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - * - * @param LegacyType[] $types - * - * @throws NotNormalizableValueException - * @throws ExtraAttributesException - * @throws MissingConstructorArgumentsException - * @throws LogicException - */ - private function validateAndDenormalizeLegacy(array $types, string $currentClass, string $attribute, mixed $data, ?string $format, array $context): mixed - { - $expectedTypes = []; - $isUnionType = \count($types) > 1; - $e = null; - $extraAttributesException = null; - $missingConstructorArgumentsException = null; - $isNullable = false; - foreach ($types as $type) { - if (null === $data && $type->isNullable()) { - return null; - } - - $collectionValueType = $type->isCollection() ? $type->getCollectionValueTypes()[0] ?? null : null; - - // Fix a collection that contains the only one element - // This is special to xml format only - if ('xml' === $format && null !== $collectionValueType && (!\is_array($data) || !\is_int(key($data)))) { - $data = [$data]; - } - - // This try-catch should cover all NotNormalizableValueException (and all return branches after the first - // exception) so we could try denormalizing all types of an union type. If the target type is not an union - // type, we will just re-throw the catched exception. - // In the case of no denormalization succeeds with an union type, it will fall back to the default exception - // with the acceptable types list. - try { - // In XML and CSV all basic datatypes are represented as strings, it is e.g. not possible to determine, - // if a value is meant to be a string, float, int or a boolean value from the serialized representation. - // That's why we have to transform the values, if one of these non-string basic datatypes is expected. - $builtinType = $type->getBuiltinType(); - if (\is_string($data) && (XmlEncoder::FORMAT === $format || CsvEncoder::FORMAT === $format)) { - if ('' === $data) { - if (LegacyType::BUILTIN_TYPE_ARRAY === $builtinType) { - return []; - } - - if (LegacyType::BUILTIN_TYPE_STRING === $builtinType) { - return ''; - } - - // Don't return null yet because Object-types that come first may accept empty-string too - $isNullable = $isNullable ?: $type->isNullable(); - } - - switch ($builtinType) { - case LegacyType::BUILTIN_TYPE_BOOL: - // according to https://www.w3.org/TR/xmlschema-2/#boolean, valid representations are "false", "true", "0" and "1" - if ('false' === $data || '0' === $data) { - $data = false; - } elseif ('true' === $data || '1' === $data) { - $data = true; - } else { - throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be bool ("%s" given).', $attribute, $currentClass, $data), $data, [LegacyType::BUILTIN_TYPE_BOOL], $context['deserialization_path'] ?? null); - } - break; - case LegacyType::BUILTIN_TYPE_INT: - if (ctype_digit(isset($data[0]) && '-' === $data[0] ? substr($data, 1) : $data)) { - $data = (int) $data; - } else { - throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be int ("%s" given).', $attribute, $currentClass, $data), $data, [LegacyType::BUILTIN_TYPE_INT], $context['deserialization_path'] ?? null); - } - break; - case LegacyType::BUILTIN_TYPE_FLOAT: - if (is_numeric($data)) { - return (float) $data; - } - - return match ($data) { - 'NaN' => \NAN, - 'INF' => \INF, - '-INF' => -\INF, - default => throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be float ("%s" given).', $attribute, $currentClass, $data), $data, [LegacyType::BUILTIN_TYPE_FLOAT], $context['deserialization_path'] ?? null), - }; - } - } - - if (is_numeric($data) && XmlEncoder::FORMAT === $format) { - // encoder parsed them wrong, so they might need to be transformed back - switch ($builtinType) { - case LegacyType::BUILTIN_TYPE_STRING: - return (string) $data; - case LegacyType::BUILTIN_TYPE_FLOAT: - return (float) $data; - case LegacyType::BUILTIN_TYPE_INT: - return (int) $data; - } - } - - if (null !== $collectionValueType && LegacyType::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) { - $builtinType = LegacyType::BUILTIN_TYPE_OBJECT; - $class = $collectionValueType->getClassName().'[]'; - - if (\count($collectionKeyType = $type->getCollectionKeyTypes()) > 0) { - $context['key_type'] = \count($collectionKeyType) > 1 ? $collectionKeyType : $collectionKeyType[0]; - } - - $context['value_type'] = $collectionValueType; - } elseif ($type->isCollection() && \count($collectionValueType = $type->getCollectionValueTypes()) > 0 && LegacyType::BUILTIN_TYPE_ARRAY === $collectionValueType[0]->getBuiltinType()) { - // get inner type for any nested array - [$innerType] = $collectionValueType; - - // note that it will break for any other builtinType - $dimensions = '[]'; - while (\count($innerType->getCollectionValueTypes()) > 0 && LegacyType::BUILTIN_TYPE_ARRAY === $innerType->getBuiltinType()) { - $dimensions .= '[]'; - [$innerType] = $innerType->getCollectionValueTypes(); - } - - if (null !== $innerType->getClassName()) { - // the builtinType is the inner one and the class is the class followed by []...[] - $builtinType = $innerType->getBuiltinType(); - $class = $innerType->getClassName().$dimensions; - } else { - // default fallback (keep it as array) - $builtinType = $type->getBuiltinType(); - $class = $type->getClassName(); - } - } else { - $builtinType = $type->getBuiltinType(); - $class = $type->getClassName(); - } - - $expectedTypes[LegacyType::BUILTIN_TYPE_OBJECT === $builtinType && $class ? $class : $builtinType] = true; - - if (LegacyType::BUILTIN_TYPE_OBJECT === $builtinType && null !== $class) { - if (!$this->serializer instanceof DenormalizerInterface) { - throw new LogicException(\sprintf('Cannot denormalize attribute "%s" for class "%s" because injected serializer is not a denormalizer.', $attribute, $class)); - } - - $childContext = $this->createChildContext($context, $attribute, $format); - if ($this->serializer->supportsDenormalization($data, $class, $format, $childContext)) { - return $this->serializer->denormalize($data, $class, $format, $childContext); - } - } - - // JSON only has a Number type corresponding to both int and float PHP types. - // PHP's json_encode, JavaScript's JSON.stringify, Go's json.Marshal as well as most other JSON encoders convert - // floating-point numbers like 12.0 to 12 (the decimal part is dropped when possible). - // PHP's json_decode automatically converts Numbers without a decimal part to integers. - // To circumvent this behavior, integers are converted to floats when denormalizing JSON based formats and when - // a float is expected. - if (LegacyType::BUILTIN_TYPE_FLOAT === $builtinType && \is_int($data) && null !== $format && str_contains($format, JsonEncoder::FORMAT)) { - return (float) $data; - } - - if (LegacyType::BUILTIN_TYPE_BOOL === $builtinType && (\is_string($data) || \is_int($data)) && ($context[self::FILTER_BOOL] ?? false)) { - return filter_var($data, \FILTER_VALIDATE_BOOL, \FILTER_NULL_ON_FAILURE); - } - - if ((LegacyType::BUILTIN_TYPE_FALSE === $builtinType && false === $data) || (LegacyType::BUILTIN_TYPE_TRUE === $builtinType && true === $data)) { - return $data; - } - - switch ($builtinType) { - case LegacyType::BUILTIN_TYPE_ARRAY: - case LegacyType::BUILTIN_TYPE_BOOL: - case LegacyType::BUILTIN_TYPE_CALLABLE: - case LegacyType::BUILTIN_TYPE_FLOAT: - case LegacyType::BUILTIN_TYPE_INT: - case LegacyType::BUILTIN_TYPE_ITERABLE: - case LegacyType::BUILTIN_TYPE_NULL: - case LegacyType::BUILTIN_TYPE_OBJECT: - case LegacyType::BUILTIN_TYPE_RESOURCE: - case LegacyType::BUILTIN_TYPE_STRING: - if (('is_'.$builtinType)($data)) { - return $data; - } - - break; - } - } catch (NotNormalizableValueException|InvalidArgumentException $e) { - if (!$isUnionType && !$isNullable) { - throw $e; - } - } catch (ExtraAttributesException $e) { - if (!$isUnionType && !$isNullable) { - throw $e; - } - - $extraAttributesException ??= $e; - } catch (MissingConstructorArgumentsException $e) { - if (!$isUnionType && !$isNullable) { - throw $e; - } - - $missingConstructorArgumentsException ??= $e; - } - } - - if ($isNullable) { - return null; - } - - if ($extraAttributesException) { - throw $extraAttributesException; - } - - if ($missingConstructorArgumentsException) { - throw $missingConstructorArgumentsException; - } - - if (!$isUnionType && $e) { - throw $e; - } - - if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) { - return $data; - } - - throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), get_debug_type($data)), $data, array_keys($expectedTypes), $context['deserialization_path'] ?? $attribute); - } - /** * Validates the submitted data and denormalizes it. * @@ -954,23 +721,13 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara return parent::denormalizeParameter($class, $parameter, $parameterName, $parameterData, $context, $format); } - // BC layer for PropertyTypeExtractorInterface::getTypes(). - // Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - if (\is_array($type)) { - $parameterData = $this->validateAndDenormalizeLegacy($type, $class->getName(), $parameterName, $parameterData, $format, $context); - } else { - $parameterData = $this->validateAndDenormalize($type, $class->getName(), $parameterName, $parameterData, $format, $context); - } - + $parameterData = $this->validateAndDenormalize($type, $class->getName(), $parameterName, $parameterData, $format, $context); $parameterData = $this->applyCallbacks($parameterData, $class->getName(), $parameterName, $format, $context); return $this->applyFilterBool($parameter, $parameterData, $context); } - /** - * @return Type|list|null - */ - private function getType(string $currentClass, string $attribute): Type|array|null + private function getType(string $currentClass, string $attribute): ?Type { if (null === $this->propertyTypeExtractor) { return null; @@ -981,7 +738,7 @@ private function getType(string $currentClass, string $attribute): Type|array|nu return false === $this->typeCache[$key] ? null : $this->typeCache[$key]; } - if (null !== $type = $this->getPropertyType($currentClass, $attribute)) { + if (null !== $type = $this->propertyTypeExtractor->getType($currentClass, $attribute)) { return $this->typeCache[$key] = $type; } @@ -991,7 +748,7 @@ private function getType(string $currentClass, string $attribute): Type|array|nu } foreach ($discriminatorMapping->getTypesMapping() as $mappedClass) { - if (null !== $type = $this->getPropertyType($mappedClass, $attribute)) { + if (null !== $type = $this->propertyTypeExtractor->getType($mappedClass, $attribute)) { return $this->typeCache[$key] = $type; } } @@ -1002,21 +759,6 @@ private function getType(string $currentClass, string $attribute): Type|array|nu return null; } - /** - * BC layer for PropertyTypeExtractorInterface::getTypes(). - * Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - * - * @return Type|list|null - */ - private function getPropertyType(string $className, string $property): Type|array|null - { - if (class_exists(Type::class) && method_exists($this->propertyTypeExtractor, 'getType')) { - return $this->propertyTypeExtractor->getType($className, $property); - } - - return $this->propertyTypeExtractor->getTypes($className, $property); - } - /** * Sets an attribute and apply the name converter if necessary. */ diff --git a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php index 96c4d259cde5f..5d00242e2b49b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Serializer\Normalizer; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\Serializer\Exception\BadMethodCallException; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; @@ -55,18 +54,14 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a $typeIdentifiers = []; if (null !== $keyType = ($context['key_type'] ?? null)) { - if ($keyType instanceof Type) { - // BC layer for type-info < 7.2 - if (method_exists(Type::class, 'getBaseType')) { - $typeIdentifiers = array_map(fn (Type $t): string => $t->getBaseType()->getTypeIdentifier()->value, $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]); - } else { - /** @var list|BuiltinType> */ - $keyTypes = $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]; - - $typeIdentifiers = array_map(fn (BuiltinType $t): string => $t->getTypeIdentifier()->value, $keyTypes); - } + // BC layer for type-info < 7.2 + if (method_exists(Type::class, 'getBaseType')) { + $typeIdentifiers = array_map(fn (Type $t): string => $t->getBaseType()->getTypeIdentifier()->value, $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]); } else { - $typeIdentifiers = array_map(fn (LegacyType $t): string => $t->getBuiltinType(), \is_array($keyType) ? $keyType : [$keyType]); + /** @var list|BuiltinType> */ + $keyTypes = $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]; + + $typeIdentifiers = array_map(fn (BuiltinType $t): string => $t->getTypeIdentifier()->value, $keyTypes); } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index 7068b8c8e6f49..7e8b79add5977 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -17,7 +17,6 @@ use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\PropertyDocBlockExtractorInterface; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\Serializer\Attribute\Context; use Symfony\Component\Serializer\Attribute\DiscriminatorMap; use Symfony\Component\Serializer\Attribute\SerializedName; @@ -437,20 +436,7 @@ public function testDenormalizeCollectionDecodedFromXmlWithTwoChildren() private function getDenormalizerForDummyCollection() { $extractor = $this->createMock(PhpDocExtractor::class); - - if (method_exists(PhpDocExtractor::class, 'getType')) { - $extractor->method('getType') - ->willReturn( - Type::list(Type::object(DummyChild::class)), - null, - ); - } else { - $extractor->method('getTypes') - ->willReturn( - [new LegacyType('array', false, null, true, new LegacyType('int'), new LegacyType('object', false, DummyChild::class))], - null - ); - } + $extractor->method('getType')->willReturn(Type::list(Type::object(DummyChild::class)), null); $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); @@ -501,20 +487,7 @@ public function testDenormalizeNotSerializableObjectToPopulate() private function getDenormalizerForStringCollection() { $extractor = $this->createMock(PhpDocExtractor::class); - - if (method_exists(PhpDocExtractor::class, 'getType')) { - $extractor->method('getType') - ->willReturn( - Type::list(Type::string()), - null, - ); - } else { - $extractor->method('getTypes') - ->willReturn( - [new LegacyType('array', false, null, true, new LegacyType('int'), new LegacyType('string'))], - null - ); - } + $extractor->method('getType')->willReturn(Type::list(Type::string()), null); $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); @@ -732,40 +705,21 @@ public function testDenormalizeBasicTypePropertiesFromXml() private function getDenormalizerForObjectWithBasicProperties() { $extractor = $this->createMock(PhpDocExtractor::class); - - if (method_exists(PhpDocExtractor::class, 'getType')) { - $extractor->method('getType') - ->willReturn( - Type::bool(), - Type::bool(), - Type::bool(), - Type::bool(), - Type::int(), - Type::int(), - Type::float(), - Type::float(), - Type::float(), - Type::float(), - Type::float(), - Type::float(), - ); - } else { - $extractor->method('getTypes') - ->willReturn( - [new LegacyType('bool')], - [new LegacyType('bool')], - [new LegacyType('bool')], - [new LegacyType('bool')], - [new LegacyType('int')], - [new LegacyType('int')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')], - [new LegacyType('float')] - ); - } + $extractor->method('getType') + ->willReturn( + Type::bool(), + Type::bool(), + Type::bool(), + Type::bool(), + Type::int(), + Type::int(), + Type::float(), + Type::float(), + Type::float(), + Type::float(), + Type::float(), + Type::float(), + ); $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); diff --git a/src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php b/src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php index 57d65696ebe95..6e61991539777 100644 --- a/src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php +++ b/src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php @@ -14,7 +14,6 @@ use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as PropertyInfoType; use Symfony\Component\TypeInfo\Type as TypeInfoType; use Symfony\Component\TypeInfo\Type\BuiltinType; use Symfony\Component\TypeInfo\Type\CollectionType; @@ -67,8 +66,8 @@ public function loadClassMetadata(ClassMetadata $metadata): bool continue; } - $types = $this->getPropertyTypes($className, $property); - if (null === $types) { + $type = $this->typeExtractor->getType($className, $property); + if (null === $type) { continue; } @@ -106,71 +105,36 @@ public function loadClassMetadata(ClassMetadata $metadata): bool $loaded = true; - // BC layer for PropertyTypeExtractorInterface::getTypes(). - // Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - if (\is_array($types)) { - $builtinTypes = []; - $nullable = false; - $scalar = true; - - foreach ($types as $type) { - $builtinTypes[] = $type->getBuiltinType(); - - if ($scalar && !\in_array($type->getBuiltinType(), ['int', 'float', 'string', 'bool'], true)) { - $scalar = false; - } - - if (!$nullable && $type->isNullable()) { - $nullable = true; - } - } + if ($hasTypeConstraint) { + continue; + } - if (!$hasTypeConstraint) { - if (1 === \count($builtinTypes)) { - if ($types[0]->isCollection() && \count($collectionValueType = $types[0]->getCollectionValueTypes()) > 0) { - [$collectionValueType] = $collectionValueType; - $this->handleAllConstraintLegacy($property, $allConstraint, $collectionValueType, $metadata); - } + // BC layer for type-info < 7.2 + if (!class_exists(NullableType::class)) { + $nullable = false; - $metadata->addPropertyConstraint($property, $this->getTypeConstraintLegacy($builtinTypes[0], $types[0])); - } elseif ($scalar) { - $metadata->addPropertyConstraint($property, new Type(type: 'scalar')); - } + if ($type instanceof UnionType && $type->isNullable()) { + $nullable = true; + $type = $type->asNonNullable(); } } else { - if ($hasTypeConstraint) { - continue; - } - - $type = $types; - - // BC layer for type-info < 7.2 - if (!class_exists(NullableType::class)) { - $nullable = false; - - if ($type instanceof UnionType && $type->isNullable()) { - $nullable = true; - $type = $type->asNonNullable(); - } - } else { - $nullable = $type->isNullable(); - - if ($type instanceof NullableType) { - $type = $type->getWrappedType(); - } - } + $nullable = $type->isNullable(); if ($type instanceof NullableType) { $type = $type->getWrappedType(); } + } - if ($type instanceof CollectionType) { - $this->handleAllConstraint($property, $allConstraint, $type->getCollectionValueType(), $metadata); - } + if ($type instanceof NullableType) { + $type = $type->getWrappedType(); + } - if (null !== $typeConstraint = $this->getTypeConstraint($type)) { - $metadata->addPropertyConstraint($property, $typeConstraint); - } + if ($type instanceof CollectionType) { + $this->handleAllConstraint($property, $allConstraint, $type->getCollectionValueType(), $metadata); + } + + if (null !== $typeConstraint = $this->getTypeConstraint($type)) { + $metadata->addPropertyConstraint($property, $typeConstraint); } if (!$nullable && !$hasNotBlankConstraint && !$hasNotNullConstraint) { @@ -181,34 +145,6 @@ public function loadClassMetadata(ClassMetadata $metadata): bool return $loaded; } - /** - * BC layer for PropertyTypeExtractorInterface::getTypes(). - * Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - * - * @return TypeInfoType|list|null - */ - private function getPropertyTypes(string $className, string $property): TypeInfoType|array|null - { - if (class_exists(TypeInfoType::class) && method_exists($this->typeExtractor, 'getType')) { - return $this->typeExtractor->getType($className, $property); - } - - return $this->typeExtractor->getTypes($className, $property); - } - - /** - * BC layer for PropertyTypeExtractorInterface::getTypes(). - * Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - */ - private function getTypeConstraintLegacy(string $builtinType, PropertyInfoType $type): Type - { - if (PropertyInfoType::BUILTIN_TYPE_OBJECT === $builtinType && null !== $className = $type->getClassName()) { - return new Type(type: $className); - } - - return new Type(type: $builtinType); - } - private function getTypeConstraint(TypeInfoType $type): ?Type { // BC layer for type-info < 7.2 @@ -289,38 +225,4 @@ private function handleAllConstraint(string $property, ?All $allConstraint, Type $allConstraint->constraints = array_merge($allConstraint->constraints, $constraints); } } - - /** - * BC layer for PropertyTypeExtractorInterface::getTypes(). - * Can be removed as soon as PropertyTypeExtractorInterface::getTypes() is removed (8.0). - */ - private function handleAllConstraintLegacy(string $property, ?All $allConstraint, PropertyInfoType $propertyInfoType, ClassMetadata $metadata): void - { - $containsTypeConstraint = false; - $containsNotNullConstraint = false; - if (null !== $allConstraint) { - foreach ($allConstraint->constraints as $constraint) { - if ($constraint instanceof Type) { - $containsTypeConstraint = true; - } elseif ($constraint instanceof NotNull) { - $containsNotNullConstraint = true; - } - } - } - - $constraints = []; - if (!$containsNotNullConstraint && !$propertyInfoType->isNullable()) { - $constraints[] = new NotNull(); - } - - if (!$containsTypeConstraint) { - $constraints[] = $this->getTypeConstraintLegacy($propertyInfoType->getBuiltinType(), $propertyInfoType); - } - - if (null === $allConstraint) { - $metadata->addPropertyConstraint($property, new All(constraints: $constraints)); - } else { - $allConstraint->constraints = array_merge($allConstraint->constraints, $constraints); - } - } } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php index ae5253a3fee53..6b4b40b7a2ae7 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php @@ -15,7 +15,6 @@ use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; -use Symfony\Component\PropertyInfo\Type as LegacyType; use Symfony\Component\TypeInfo\Type; use Symfony\Component\Validator\Constraints\All; use Symfony\Component\Validator\Constraints\Iban; @@ -62,7 +61,6 @@ public function testLoadClassMetadata() private int $i = 0; private int $j = 0; private array $types; - private array $legacyTypes; public function getType(string $class, string $property, array $context = []): ?Type { @@ -86,29 +84,6 @@ public function getType(string $class, string $property, array $context = []): ? return $type; } - - public function getTypes(string $class, string $property, array $context = []): ?array - { - $this->legacyTypes ??= [ - [new LegacyType('string', true)], - [new LegacyType('string')], - [new LegacyType('string', true), new LegacyType('int'), new LegacyType('bool')], - [new LegacyType('object', true, Entity::class)], - [new LegacyType('array', true, null, true, null, new LegacyType('object', false, Entity::class))], - [new LegacyType('array', true, null, true)], - [new LegacyType('float', true)], // The existing constraint is float - [new LegacyType('string', true)], - [new LegacyType('string', true)], - [new LegacyType('array', true, null, true, null, new LegacyType('float'))], - [new LegacyType('string')], - [new LegacyType('string')], - ]; - - $legacyType = $this->legacyTypes[$this->j]; - ++$this->j; - - return $legacyType; - } }; $propertyAccessExtractor = $this->createMock(PropertyAccessExtractorInterface::class); @@ -240,11 +215,6 @@ public function getType(string $class, string $property, array $context = []): ? { return Type::string(); } - - public function getTypes(string $class, string $property, array $context = []): ?array - { - return [new LegacyType('string')]; - } }; $propertyAccessExtractor = $this->createMock(PropertyAccessExtractorInterface::class); @@ -279,11 +249,6 @@ public function getType(string $class, string $property, array $context = []): ? { return Type::string(); } - - public function getTypes(string $class, string $property, array $context = []): ?array - { - return [new LegacyType('string')]; - } }; }