8000 bug #58885 [PropertyInfo][Serializer][TypeInfo][Validator] TypeInfo 7… · symfony/symfony@75da5aa · GitHub
[go: up one dir, main page]

Skip to content

Commit 75da5aa

Browse files
bug #58885 [PropertyInfo][Serializer][TypeInfo][Validator] TypeInfo 7.1 compatibility (mtarld)
This PR was merged into the 7.2 branch. Discussion ---------- [PropertyInfo][Serializer][TypeInfo][Validator] TypeInfo 7.1 compatibility | Q | A | ------------- | --- | Branch? | 7.2 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | | License | MIT Upmerge #58872 to allow DoctrineBridge, Validator, Serializer and PropertyInfo to be compatible with TypeInfo 7.1 Commits ------- d3acdeb [TypeInfo][Serializer][PropertyInfo][Validator] TypeInfo 7.1 compatibility
2 parents 31f22b8 + d3acdeb commit 75da5aa
< 8000 /pre>

File tree

12 files changed

+146
-33
lines changed

src/Symfony/Bridge/Doctrine/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"symfony/security-core": "^6.4|^7.0",
4040
"symfony/stopwatch": "^6.4|^7.0",
4141
"symfony/translation": "^6.4|^7.0",
42-
"symfony/type-info": "^7.2",
42+
"symfony/type-info": "^7.1",
4343
"symfony/uid": "^6.4|^7.0",
4444
"symfony/validator": "^6.4|^7.0",
4545
"symfony/var-dumper": "^6.4|^7.0",

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"symfony/string": "^6.4|^7.0",
6565
"symfony/translation": "^6.4|^7.0",
6666
"symfony/twig-bundle": "^6.4|^7.0",
67-
"symfony/type-info": "^7.2",
67+
"symfony/type-info": "^7.1",
6868
"symfony/validator": "^6.4|^7.0",
6969
"symfony/workflow": "^6.4|^7.0",
7070
"symfony/yaml": "^6.4|^7.0",

src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait;
2828
use Symfony\Component\PropertyInfo\Type as LegacyType;
2929
use Symfony\Component\TypeInfo\Type;
30+
use Symfony\Component\TypeInfo\Type\NullableType;
3031

3132
/**
3233
* @author Kévin Dunglas <dunglas@gmail.com>
@@ -562,7 +563,14 @@ public static function typeProvider(): iterable
562563
yield ['f', Type::list(Type::object(\DateTimeImmutable::class)), null, null];
563564
yield ['g', Type::nullable(Type::array()), 'Nullable array.', null];
564565
yield ['h', Type::nullable(Type::string()), null, null];
565-
yield ['i', Type::union(Type::int(), Type::string(), Type::null()), null, null];
566+
567+
// BC layer for type-info < 7.2
568+
if (!class_exists(NullableType::class)) {
569+
yield ['i', Type::union(Type::int(), Type::string(), Type::null()), null, null];
570+
} else {
571+
yield ['i', Type::nullable(Type::union(Type::int(), Type::string())), null, null];
572+
}
573+
566574
yield ['j', Type::nullable(Type::object(\DateTimeImmutable::class)), null, null];
567575
yield ['nullableCollectionOfNonNullableElements', Type::nullable(Type::list(Type::int())), null, null];
568576
yield ['donotexist', null, null, null];
@@ -629,7 +637,14 @@ public static function typeWithNoPrefixesProvider()
629637
yield ['f', null];
630638
yield ['g', Type::nullable(Type::array())];
631639
yield ['h', Type::nullable(Type::string())];
632-
yield ['i', Type::union(Type::int(), Type::string(), Type::null())];
640+
641+
// BC layer for type-info < 7.2
642+
if (!class_exists(NullableType::class)) {
643+
yield ['i', Type::union(Type::int(), Type::string(), Type::null())];
644+
} else {
645+
yield ['i', Type::nullable(Type::union(Type::int(), Type::string()))];
646+
}
647+
633648
yield ['j', Type::nullable(Type::object(\DateTimeImmutable::class))];
634649
yield ['nullableCollectionOfNonNullableElements', Type::nullable(Type::list(Type::int()))];
635650
yield ['donotexist', null];
@@ -693,7 +708,14 @@ public static function typeWithCustomPrefixesProvider(): iterable
693708
yield ['f', Type::list(Type::object(\DateTimeImmutable::class))];
694709
yield ['g', Type::nullable(Type::array())];
695710
yield ['h', Type::nullable(Type::string())];
696-
yield ['i', Type::nullable(Type::union(Type::int(), Type::string()))];
711+
712+
// BC layer for type-info < 7.2
713+
if (!class_exists(NullableType::class)) {
714+
yield ['i', Type::union(Type::int(), Type::string(), Type::null())];
715+
} else {
716+
yield ['i', Type::nullable(Type::union(Type::int(), Type::string()))];
717+
}
718+
697719
yield ['j', Type::nullable(Type::object(\DateTimeImmutable::class))];
698720
yield ['nullableCollectionOfNonNullableElements', Type::nullable(Type::list(Type::int()))];
699721
yield ['nonNullableCollectionOfNullableElements', Type::list(Type::nullable(Type::int()))];

src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use Symfony\Component\PropertyInfo\Type as LegacyType;
3737
use Symfony\Component\TypeInfo\Exception\LogicException;
3838
use Symfony\Component\TypeInfo\Type;
39+
use Symfony\Component\TypeInfo\Type\WrappingTypeInterface;
3940

4041
require_once __DIR__.'/../Fixtures/Extractor/DummyNamespace.php';
4142

@@ -869,7 +870,14 @@ public function testPseudoTypes(string $property, ?Type $type)
869870
public static function pseudoTypesProvider(): iterable
870871
{
871872
yield ['classString', Type::string()];
872-
yield ['classStringGeneric', Type::string()];
873+
874+
// BC layer for type-info < 7.2
875+
if (!interface_exists(WrappingTypeInterface::class)) {
876+
yield ['classStringGeneric', Type::generic(Type::string(), Type::object(\stdClass::class))];
877+
} else {
878+
yield ['classStringGeneric', Type::string()];
879+
}
880+
873881
yield ['htmlEscapedString', Type::string()];
874882
yield ['lowercaseString', Type::string()];
875883
yield ['nonEmptyLowercaseString', Type::string()];

src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Symfony\Component\PropertyInfo\Tests\Fixtures\SnakeCaseDummy;
3434
use Symfony\Component\PropertyInfo\Type as LegacyType;
3535
use Symfony\Component\TypeInfo\Type;
36+
use Symfony\Component\TypeInfo\Type\NullableType;
3637

3738
/**
3839
* @author Kévin Dunglas <dunglas@gmail.com>
@@ -771,7 +772,14 @@ public static function php80TypesProvider(): iterable
771772
yield ['foo', Type::nullable(Type::array())];
772773
yield ['bar', Type::nullable(Type::int())];
773774
yield ['timeout', Type::union(Type::int(), Type::float())];
774-
yield ['optional', Type::nullable(Type::union(Type::float(), Type::int()))];
775+
776+
// BC layer for type-info < 7.2
777+
if (!class_exists(NullableType::class)) {
778+
yield ['optional', Type::union(Type::nullable(Type::int()), Type::nullable(Type::float()))];
779+
} else {
780+
yield ['optional', Type::nullable(Type::union(Type::float(), Type::int()))];
781+
}
782+
775783
yield ['string', Type::union(Type::string(), Type::object(\Stringable::class))];
776784
yield ['payload', Type::mixed()];
777785
yield ['data', Type::mixed()];

src/Symfony/Component/PropertyInfo/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"require": {
2626
"php": ">=8.2",
2727
"symfony/string": "^6.4|^7.0",
28-
"symfony/type-info": "^7.2"
28+
"symfony/type-info": "^7.1"
2929
},
3030
"require-dev": {
3131
"symfony/serializer": "^6.4|^7.0",

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use Symfony\Component\Serializer\Mapping\ClassMetadataInterface;
3333
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
3434
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
35+
use Symfony\Component\TypeInfo\Exception\LogicException as TypeInfoLogicException;
3536
use Symfony\Component\TypeInfo\Type;
3637
use Symfony\Component\TypeInfo\Type\BuiltinType;
3738
use Symfony\Component\TypeInfo\Type\CollectionType;
@@ -646,6 +647,14 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass
646647
private function validateAndDenormalize(Type $type, string $currentClass, string $attribute, mixed $data, ?string $format, array $context): mixed
647648
{
648649
$expectedTypes = [];
650+
651+
// BC layer for type-info < 7.2
652+
if (method_exists(Type::class, 'asNonNullable')) {
653+
$isUnionType = $type->asNonNullable() instanceof UnionType;
654+
} else {
655+
$isUnionType = $type instanceof UnionType;
656+
}
657+
649658
$e = null;
650659
$extraAttributesException = null;
651660
$missingConstructorArgumentsException = null;
@@ -667,14 +676,23 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
667676
$collectionValueType = $t->getCollectionValueType();
668677
}
669678

670-
while ($t instanceof WrappingTypeInterface) {
671-
$t = $t->getWrappedType();
679+
// BC layer for type-info < 7.2
680+
if (method_exists(Type::class, 'getBaseType')) {
681+
$t = $t->getBaseType();
682+
} else {
683+
while ($t instanceof WrappingTypeInterface) {
684+
$t = $t->getWrappedType();
685+
}
672686
}
673687

674688
// Fix a collection that contains the only one element
675689
// This is special to xml format only
676-
if ('xml' === $format && $collectionValueType && !$collectionValueType->isIdentifiedBy(TypeIdentifier::MIXED) && (!\is_array($data) || !\is_int(key($data)))) {
677-
$data = [$data];
690+
if ('xml' === $format && $collectionValueType && (!\is_array($data) || !\is_int(key($data)))) {
691+
// BC layer for type-info < 7.2
692+
$isMixedType = method_exists(Type::class, 'isA') ? $collectionValueType->isA(TypeIdentifier::MIXED) : $collectionValueType->isIdentifiedBy(TypeIdentifier::MIXED);
693+
if (!$isMixedType) {
694+
$data = [$data];
695+
}
678696
}
679697

680698
// This try-catch should cover all NotNormalizableValueException (and all return branches after the first
@@ -731,17 +749,31 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
731749
}
732750

733751
if ($collectionValueType) {
734-
$collectionValueBaseType = $collectionValueType;
735-
while ($collectionValueBaseType instanceof WrappingTypeInterface) {
736-
$collectionValueBaseType = $collectionValueBaseType->getWrappedType();
752+
try {
753+
$collectionValueBaseType = $collectionValueType;
754+
755+
// BC layer for type-info < 7.2
756+
if (!interface_exists(WrappingTypeInterface::class)) {
757+
$collectionValueBaseType = $collectionValueType->getBaseType();
758+
} else {
759+
while ($collectionValueBaseType instanceof WrappingTypeInterface) {
760+
$collectionValueBaseType = $collectionValueBaseType->getWrappedType();
761+
}
762+
}
763+
} catch (TypeInfoLogicException) {
764+
$collectionValueBaseType = Type::mixed();
737765
}
738766

739767
if ($collectionValueBaseType instanceof ObjectType) {
740768
$typeIdentifier = TypeIdentifier::OBJECT;
741769
$class = $collectionValueBaseType->getClassName().'[]';
742770
$context['key_type'] = $collectionKeyType;
743771
$context['value_type'] = $collectionValueType;
744-
} elseif ($collectionValueBaseType instanceof BuiltinType && TypeIdentifier::ARRAY === $collectionValueBaseType->getTypeIdentifier()) {
772+
} elseif (
773+
// BC layer for type-info < 7.2
774+
!class_exists(NullableType::class) && TypeIdentifier::ARRAY === $collectionValueBaseType->getTypeIdentifier()
775+
|| $collectionValueBaseType instanceof BuiltinType && TypeIdentifier::ARRAY === $collectionValueBaseType->getTypeIdentifier()
776+
) {
745777
// get inner type for any nested array
746778
$innerType = $collectionValueType;
747779
if ($innerType instanceof NullableType) {
@@ -871,8 +903,15 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
871903
throw $missingConstructorArgumentsException;
872904
}
873905

874-
if ($e && !($type instanceof UnionType && !$type instanceof NullableType)) {
875-
throw $e;
906+
// BC layer for type-info < 7.2
907+
if (!class_exists(NullableType::class)) {
908+
if (!$isUnionType && $e) {
909+
throw $e;
910+
}
911+
} else {
912+
if ($e && !($type instanceof UnionType && !$type instanceof NullableType)) {
913+
throw $e;
914+
}
876915
}
877916

878917
if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) {

src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,15 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
5656
$typeIdentifiers = [];
5757
if (null !== $keyType = ($context['key_type'] ?? null)) {
5858
if ($keyType instanceof Type) {
59-
/** @var list<BuiltinType<TypeIdentifier::INT>|BuiltinType<TypeIdentifier::STRING>> */
60-
$keyTypes = $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType];
61-
62-
$typeIdentifiers = array_map(fn (BuiltinType $t): string => $t->getTypeIdentifier()->value, $keyTypes);
59+
// BC layer for type-info < 7.2
60+
if (method_exists(Type::class, 'getBaseType')) {
61+
$typeIdentifiers = array_map(fn (Type $t): string => $t->getBaseType()->getTypeIdentifier()->value, $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]);
62+
} else {
63+
/** @var list<BuiltinType<TypeIdentifier::INT>|BuiltinType<TypeIdentifier::STRING>> */
64+
$keyTypes = $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType];
65+
66+
$typeIdentifiers = array_map(fn (BuiltinType $t): string => $t->getTypeIdentifier()->value, $keyTypes);
67+
}
6368
} else {
6469
$typeIdentifiers = array_map(fn (LegacyType $t): string => $t->getBuiltinType(), \is_array($keyType) ? $keyType : [$keyType]);
6570
}

src/Symfony/Component/Serializer/composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"symfony/property-access": "^6.4|^7.0",
3939
"symfony/property-info": "^6.4|^7.0",
4040
"symfony/translation-contracts": "^2.5|^3",
41-
"symfony/type-info": "^7.2",
41+
"symfony/type-info": "^7.1",
4242
"symfony/uid": "^6.4|^7.0",
4343
"symfony/validator": "^6.4|^7.0",
4444
"symfony/var-dumper": "^6.4|^7.0",
@@ -51,7 +51,6 @@
5151
"symfony/dependency-injection": "<6.4",
5252
"symfony/property-access": "<6.4",
5353
"symfony/property-info": "<6.4",
54-
"symfony/type-info": "<7.2",
5554
"symfony/uid": "<6.4",
5655
"symfony/validator": "<6.4",
5756
"symfony/yaml": "<6.4"

src/Symfony/Component/TypeInfo/composer.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,11 @@
3030
},
3131
"require-dev": {
3232
"phpstan/phpdoc-parser": "^1.0|^2.0",
33-
"symfony/dependency-injection": "^6.4|^7.0",
34-
"symfony/property-info": "^7.2"
33+
"symfony/dependency-injection": "^6.4|^7.0"
3534
},
3635
"conflict": {
3736
"phpstan/phpdoc-parser": "<1.0",
38-
"symfony/dependency-injection": "<6.4",
39-
"symfony/property-info": ">=7.1,<7.1.9",
40-
"symfony/serializer": ">=7.1,<7.1.9",
41-
"symfony/validator": ">=7.1,<7.1.9"
37+
"symfony/dependency-injection": "<6.4"
4238
},
4339
"autoload": {
4440
"psr-4": { "Symfony\\Component\\TypeInfo\\": "" },

src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
use Symfony\Component\TypeInfo\Type\BuiltinType;
2020
use Symfony\Component\TypeInfo\Type\CollectionType;
2121
use Symfony\Component\TypeInfo\Type\CompositeTypeInterface;
22+
use Symfony\Component\TypeInfo\Type\IntersectionType;
2223
use Symfony\Component\TypeInfo\Type\NullableType;
2324
use Symfony\Component\TypeInfo\Type\ObjectType;
24-
use Symfony\Component\TypeInfo\TypeIdentifier;
25+
use Symfony\Component\TypeInfo\Type\UnionType;
2526
use Symfony\Component\TypeInfo\Type\WrappingTypeInterface;
27+
use Symfony\Component\TypeInfo\TypeIdentifier;
2628
use Symfony\Component\Validator\Constraints\All;
2729
use Symfony\Component\Validator\Constraints\NotBlank;
2830
use Symfony\Component\Validator\Constraints\NotNull;
@@ -141,7 +143,22 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
141143
}
142144

143145
$type = $types;
144-
$nullable = $type->isNullable();
146+
147+
// BC layer for type-info < 7.2
148+
if (!class_exists(NullableType::class)) {
149+
$nullable = false;
150+
151+
if ($type instanceof UnionType && $type->isNullable()) {
152+
$nullable = true;
153+
$type = $type->asNonNullable();
154+
}
155+
} else {
156+
$nullable = $type->isNullable();
157+
158+
if ($type instanceof NullableType) {
159+
$type = $type->getWrappedType();
160+
}
161+
}
145162

146163
if ($type instanceof NullableType) {
147164
$type = $type->getWrappedType();
@@ -194,6 +211,25 @@ private function getTypeConstraintLegacy(string $builtinType, PropertyInfoType $
194211

195212
private function getTypeConstraint(TypeInfoType $type): ?Type
196213
{
214+
// BC layer for type-info < 7.2
215+
if (!interface_exists(CompositeTypeInterface::class)) {
216+
if ($type instanceof UnionType || $type instanceof IntersectionType) {
217+
return ($type->isA(TypeIdentifier::INT) || $type->isA(TypeIdentifier::FLOAT) || $type->isA(TypeIdentifier::STRING) || $type->isA(TypeIdentifier::BOOL)) ? new Type(['type' => 'scalar']) : null;
218+
}
219+
220+
$baseType = $type->getBaseType();
221+
222+
if ($baseType instanceof ObjectType) {
223+
return new Type(['type' => $baseType->getClassName()]);
224+
}
225+
226+
if (TypeIdentifier::MIXED !== $baseType->getTypeIdentifier()) {
227+
return new Type(['type' => $baseType->getTypeIdentifier()->value]);
228+
}
229+
230+
return null;
231+
}
232+
197233
if ($type instanceof CompositeTypeInterface) {
198234
return $type->isIdentifiedBy(
199235
TypeIdentifier::INT,

src/Symfony/Component/Validator/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"symfony/property-access": "^6.4|^7.0",
4040
"symfony/property-info": "^6.4|^7.0",
4141
"symfony/translation": "^6.4.3|^7.0.3",
42-
"symfony/type-info": "^7.2-RC1",
42+
"symfony/type-info": "^7.1",
4343
"egulias/email-validator": "^2.1.10|^3|^4"
4444
},
4545
"conflict": {

0 commit comments

Comments
 (0)
0