3434use Symfony \Component \Serializer \NameConverter \NameConverterInterface ;
3535use Symfony \Component \TypeInfo \Exception \LogicException as TypeInfoLogicException ;
3636use Symfony \Component \TypeInfo \Type ;
37+ use Symfony \Component \TypeInfo \Type \BuiltinType ;
3738use Symfony \Component \TypeInfo \Type \CollectionType ;
3839use Symfony \Component \TypeInfo \Type \IntersectionType ;
40+ use Symfony \Component \TypeInfo \Type \NullableType ;
3941use Symfony \Component \TypeInfo \Type \ObjectType ;
4042use Symfony \Component \TypeInfo \Type \UnionType ;
43+ use Symfony \Component \TypeInfo \Type \WrappingTypeInterface ;
4144use Symfony \Component \TypeInfo \TypeIdentifier ;
4245
4346/**
@@ -644,7 +647,14 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass
644647 private function validateAndDenormalize (Type $ type , string $ currentClass , string $ attribute , mixed $ data , ?string $ format , array $ context ): mixed
645648 {
646649 $ expectedTypes = [];
647- $ isUnionType = $ type ->asNonNullable () instanceof UnionType;
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+
648658 $ e = null ;
649659 $ extraAttributesException = null ;
650660 $ missingConstructorArgumentsException = null ;
@@ -667,12 +677,23 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
667677 $ collectionValueType = $ t ->getCollectionValueType ();
668678 }
669679
670- $ t = $ t ->getBaseType ();
680+ // BC layer for type-info < 7.2
681+ if (method_exists (Type::class, 'getBaseType ' )) {
682+ $ t = $ t ->getBaseType ();
683+ } else {
684+ while ($ t instanceof WrappingTypeInterface) {
685+ $ t = $ t ->getWrappedType ();
686+ }
687+ }
671688
672689 // Fix a collection that contains the only one element
673690 // This is special to xml format only
674- if ('xml ' === $ format && $ collectionValueType && !$ collectionValueType ->isA (TypeIdentifier::MIXED ) && (!\is_array ($ data ) || !\is_int (key ($ data )))) {
675- $ data = [$ data ];
691+ if ('xml ' === $ format && $ collectionValueType && (!\is_array ($ data ) || !\is_int (key ($ data )))) {
692+ // BC layer for type-info < 7.2
693+ $ isMixedType = method_exists (Type::class, 'isA ' ) ? $ collectionValueType ->isA (TypeIdentifier::MIXED ) : $ collectionValueType ->isIdentifiedBy (TypeIdentifier::MIXED );
694+ if (!$ isMixedType ) {
695+ $ data = [$ data ];
696+ }
676697 }
677698
678699 // This try-catch should cover all NotNormalizableValueException (and all return branches after the first
@@ -695,7 +716,10 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
695716 return '' ;
696717 }
697718
698- $ isNullable = $ isNullable ?: $ type ->isNullable ();
719+ // BC layer for type-info < 7.2
720+ if (method_exists (Type::class, 'isNullable ' )) {
721+ $ isNullable = $ isNullable ?: $ type ->isNullable ();
722+ }
699723 }
700724
701725 switch ($ typeIdentifier ) {
@@ -732,7 +756,16 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
732756
733757 if ($ collectionValueType ) {
734758 try {
735- $ collectionValueBaseType = $ collectionValueType ->getBaseType ();
759+ $ collectionValueBaseType = $ collectionValueType ;
760+
761+ // BC layer for type-info < 7.2
762+ if (!interface_exists (WrappingTypeInterface::class)) {
763+ $ collectionValueBaseType = $ collectionValueType ->getBaseType ();
764+ } else {
765+ while ($ collectionValueBaseType instanceof WrappingTypeInterface) {
766+ $ collectionValueBaseType = $ collectionValueBaseType ->getWrappedType ();
767+ }
768+ }
736769 } catch (TypeInfoLogicException ) {
737770 $ collectionValueBaseType = Type::mixed ();
738771 }
@@ -742,15 +775,29 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
742775 $ class = $ collectionValueBaseType ->getClassName ().'[] ' ;
743776 $ context ['key_type ' ] = $ collectionKeyType ;
744777 $ context ['value_type ' ] = $ collectionValueType ;
745- } elseif (TypeIdentifier::ARRAY === $ collectionValueBaseType ->getTypeIdentifier ()) {
778+ } elseif (
779+ // BC layer for type-info < 7.2
780+ !class_exists (NullableType::class) && TypeIdentifier::ARRAY === $ collectionValueBaseType ->getTypeIdentifier ()
781+ || $ collectionValueBaseType instanceof BuiltinType && TypeIdentifier::ARRAY === $ collectionValueBaseType ->getTypeIdentifier ()
782+ ) {
746783 // get inner type for any nested array
747784 $ innerType = $ collectionValueType ;
785+ if ($ innerType instanceof NullableType) {
786+ $ innerType = $ innerType ->getWrappedType ();
787+ }
748788
749789 // note that it will break for any other builtinType
750790 $ dimensions = '[] ' ;
751791 while ($ innerType instanceof CollectionType) {
752792 $ dimensions .= '[] ' ;
753793 $ innerType = $ innerType ->getCollectionValueType ();
794+ if ($ innerType instanceof NullableType) {
795+ $ innerType = $ innerType ->getWrappedType ();
796+ }
797+ }
798+
799+ while ($ innerType instanceof WrappingTypeInterface) {
800+ $ innerType = $ innerType ->getWrappedType ();
754801 }
755802
756803 if ($ innerType instanceof ObjectType) {
@@ -862,8 +909,15 @@ private function validateAndDenormalize(Type $type, string $currentClass, string
862909 throw $ missingConstructorArgumentsException ;
863910 }
864911
865- if (!$ isUnionType && $ e ) {
866- throw $ e ;
912+ // BC layer for type-info < 7.2
913+ if (!class_exists (NullableType::class)) {
914+ if (!$ isUnionType && $ e ) {
915+ throw $ e ;
916+ }
917+ } else {
918+ if ($ e && !($ type instanceof UnionType && !$ type instanceof NullableType)) {
919+ throw $ e ;
920+ }
867921 }
868922
869923 if ($ context [self ::DISABLE_TYPE_ENFORCEMENT ] ?? $ this ->defaultContext [self ::DISABLE_TYPE_ENFORCEMENT ] ?? false ) {
0 commit comments