11
11
12
12
namespace Symfony \Component \PropertyInfo ;
13
13
14
+ use Symfony \Component \TypeInfo \Type as TypeInfoType ;
15
+ use Symfony \Component \TypeInfo \Type \BuiltinType ;
16
+ use Symfony \Component \TypeInfo \Type \GenericType ;
17
+ use Symfony \Component \TypeInfo \Type \IntersectionType ;
18
+ use Symfony \Component \TypeInfo \Type \ObjectType ;
19
+ use Symfony \Component \TypeInfo \Type \UnionType ;
20
+
21
+ trigger_deprecation ('symfony/property-info ' , '7.1 ' , 'The "%s" class is deprecated. Use "%s" of "symfony/type-info" component instead. ' , Type::class, TypeInfoType::class);
22
+
14
23
/**
15
24
* Type value object (immutable).
16
25
*
17
26
* @author Kévin Dunglas <[email protected] >
18
27
*
19
28
* @final
29
+ *
30
+ * @deprecated since Symfony 7.1, use "Symfony\Component\TypeInfo\Type" of "symfony/type-info" component instead.
20
31
*/
21
32
class Type
22
33
{
23
- public const BUILTIN_TYPE_INT = ' int ' ;
24
- public const BUILTIN_TYPE_FLOAT = ' float ' ;
25
- public const BUILTIN_TYPE_STRING = ' string ' ;
26
- public const BUILTIN_TYPE_BOOL = ' bool ' ;
27
- public const BUILTIN_TYPE_RESOURCE = ' resource ' ;
28
- public const BUILTIN_TYPE_OBJECT = ' object ' ;
29
- public const BUILTIN_TYPE_ARRAY = ' array ' ;
30
- public const BUILTIN_TYPE_NULL = ' null ' ;
31
- public const BUILTIN_TYPE_FALSE = ' false ' ;
32
- public const BUILTIN_TYPE_TRUE = ' true ' ;
33
- public const BUILTIN_TYPE_CALLABLE = ' callable ' ;
34
- public const BUILTIN_TYPE_ITERABLE = ' iterable ' ;
34
+ public const BUILTIN_TYPE_INT = TypeInfoType:: BUILTIN_TYPE_INT ;
35
+ public const BUILTIN_TYPE_FLOAT = TypeInfoType:: BUILTIN_TYPE_FLOAT ;
36
+ public const BUILTIN_TYPE_STRING = TypeInfoType:: BUILTIN_TYPE_STRING ;
37
+ public const BUILTIN_TYPE_BOOL = TypeInfoType:: BUILTIN_TYPE_BOOL ;
38
+ public const BUILTIN_TYPE_RESOURCE = TypeInfoType:: BUILTIN_TYPE_RESOURCE ;
39
+ public const BUILTIN_TYPE_OBJECT = TypeInfoType:: BUILTIN_TYPE_OBJECT ;
40
+ public const BUILTIN_TYPE_ARRAY = TypeInfoType:: BUILTIN_TYPE_ARRAY ;
41
+ public const BUILTIN_TYPE_NULL = TypeInfoType:: BUILTIN_TYPE_NULL ;
42
+ public const BUILTIN_TYPE_FALSE = TypeInfoType:: BUILTIN_TYPE_FALSE ;
43
+ public const BUILTIN_TYPE_TRUE = TypeInfoType:: BUILTIN_TYPE_TRUE ;
44
+ public const BUILTIN_TYPE_CALLABLE = TypeInfoType:: BUILTIN_TYPE_CALLABLE ;
45
+ public const BUILTIN_TYPE_ITERABLE = TypeInfoType:: BUILTIN_TYPE_ITERABLE ;
35
46
36
47
/**
37
48
* List of PHP builtin types.
38
49
*
39
50
* @var string[]
40
51
*/
41
52
public static array $ builtinTypes = [
42
- self ::BUILTIN_TYPE_INT ,
43
- self ::BUILTIN_TYPE_FLOAT ,
44
- self ::BUILTIN_TYPE_STRING ,
45
- self ::BUILTIN_TYPE_BOOL ,
46
- self ::BUILTIN_TYPE_RESOURCE ,
47
- self ::BUILTIN_TYPE_OBJECT ,
48
- self ::BUILTIN_TYPE_ARRAY ,
49
- self ::BUILTIN_TYPE_CALLABLE ,
50
- self ::BUILTIN_TYPE_FALSE ,
51
- self ::BUILTIN_TYPE_TRUE ,
52
- self ::BUILTIN_TYPE_NULL ,
53
- self ::BUILTIN_TYPE_ITERABLE ,
53
+ TypeInfoType ::BUILTIN_TYPE_INT ,
54
+ TypeInfoType ::BUILTIN_TYPE_FLOAT ,
55
+ TypeInfoType ::BUILTIN_TYPE_STRING ,
56
+ TypeInfoType ::BUILTIN_TYPE_BOOL ,
57
+ TypeInfoType ::BUILTIN_TYPE_RESOURCE ,
58
+ TypeInfoType ::BUILTIN_TYPE_OBJECT ,
59
+ TypeInfoType ::BUILTIN_TYPE_ARRAY ,
60
+ TypeInfoType ::BUILTIN_TYPE_CALLABLE ,
61
+ TypeInfoType ::BUILTIN_TYPE_FALSE ,
62
+ TypeInfoType ::BUILTIN_TYPE_TRUE ,
63
+ TypeInfoType ::BUILTIN_TYPE_NULL ,
64
+ TypeInfoType ::BUILTIN_TYPE_ITERABLE ,
54
65
];
55
66
56
67
/**
@@ -59,54 +70,59 @@ class Type
59
70
* @var string[]
60
71
*/
61
72
public static array $ builtinCollectionTypes = [
62
- self ::BUILTIN_TYPE_ARRAY ,
63
- self ::BUILTIN_TYPE_ITERABLE ,
73
+ TypeInfoType ::BUILTIN_TYPE_ARRAY ,
74
+ TypeInfoType ::BUILTIN_TYPE_ITERABLE ,
64
75
];
65
76
66
- private string $ builtinType ;
67
- private bool $ nullable ;
68
- private ?string $ class ;
69
- private bool $ collection ;
70
- private array $ collectionKeyType ;
71
- private array $ collectionValueType ;
77
+ private TypeInfoType $ internalType ;
72
78
73
79
/**
74
80
* @param Type[]|Type|null $collectionKeyType
75
81
* @param Type[]|Type|null $collectionValueType
76
82
*
77
83
* @throws \InvalidArgumentException
78
84
*/
79
- public function __construct (string $ builtinType , bool $ nullable = false , string $ class = null , bool $ collection = false , array |Type $ collectionKeyType = null , array |Type $ collectionValueType = null )
85
+ public function __construct (string $ builtinType , bool $ nullable = false , string $ class = null , bool $ collection = false , array |self $ collectionKeyType = null , array |self $ collectionValueType = null )
80
86
{
81
- if (!\in_array ($ builtinType , self ::$ builtinTypes )) {
82
- throw new \InvalidArgumentException (sprintf ('"%s" is not a valid PHP type. ' , $ builtinType ));
83
- }
87
+ $ genericTypes = [];
84
88
85
- $ this ->builtinType = $ builtinType ;
86
- $ this ->nullable = $ nullable ;
87
- $ this ->class = $ class ;
88
- $ this ->collection = $ collection ;
89
- $ this ->collectionKeyType = $ this ->validateCollectionArgument ($ collectionKeyType , 5 , '$collectionKeyType ' ) ?? [];
90
- $ this ->collectionValueType = $ this ->validateCollectionArgument ($ collectionValueType , 6 , '$collectionValueType ' ) ?? [];
91
- }
89
+ $ collectionKeyType = $ this ->validateCollectionArgument ($ collectionKeyType , 5 , '$collectionKeyType ' ) ?? [];
90
+ $ collectionValueType = $ this ->validateCollectionArgument ($ collectionValueType , 6 , '$collectionValueType ' ) ?? [];
92
91
93
- private function validateCollectionArgument (array |Type |null $ collectionArgument , int $ argumentIndex , string $ argumentName ): ?array
94
- {
95
- if (null === $ collectionArgument ) {
96
- return null ;
92
+ if (null !== $ collectionKeyType && [] !== $ collectionKeyType ) {
93
+ if (\is_array ($ collectionKeyType )) {
94
+ $ collectionKeyType = array_unique (array_map (fn ($ t ): TypeInfoType => $ t ->getTypeInfoType (), $ collectionKeyType ));
95
+ $ genericTypes [] = \count ($ collectionKeyType ) > 1 ? TypeInfoType::union (...$ collectionKeyType ) : $ collectionKeyType [0 ];
96
+ } else {
97
+ $ genericTypes [] = $ collectionKeyType ->getTypeInfoType ();
98
+ }
97
99
}
98
100
99
- if (\is_array ($ collectionArgument )) {
100
- foreach ($ collectionArgument as $ type ) {
101
- if (!$ type instanceof self) {
102
- 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 )));
103
- }
101
+ if (null !== $ collectionValueType && [] !== $ collectionValueType ) {
102
+ if ([] === $ genericTypes ) {
103
+ $ genericTypes [] = TypeInfoType::int ();
104
104
}
105
105
106
- return $ collectionArgument ;
106
+ if (\is_array ($ collectionValueType )) {
107
+ $ collectionValueType = array_unique (array_map (fn ($ t ): TypeInfoType => $ t ->getTypeInfoType (), $ collectionValueType ));
108
+ $ genericTypes [] = \count ($ collectionValueType ) > 1 ? TypeInfoType::union (...$ collectionValueType ) : $ collectionValueType [0 ];
109
+ } else {
110
+ $ genericTypes [] = $ collectionValueType ->getTypeInfoType ();
111
+ }
107
112
}
108
113
109
- return [$ collectionArgument ];
114
+ $ this ->internalType = null !== $ class ? new ObjectType ($ class ) : new BuiltinType ($ builtinType );
115
+ $ this ->internalType ->isCollection = $ collection ;
116
+
117
+ if (\count ($ genericTypes )) {
118
+ $ this ->internalType = TypeInfoType::generic ($ this ->internalType , ...$ genericTypes );
119
+ $ this ->internalType ->isCollection = $ collection ;
120
+ }
121
+
122
+ if ($ nullable ) {
123
+ $ this ->internalType = TypeInfoType::nullable ($ this ->internalType );
124
+ $ this ->internalType ->isCollection = $ collection ;
125
+ }
110
126
}
111
127
112
128
/**
@@ -116,12 +132,15 @@ private function validateCollectionArgument(array|Type|null $collectionArgument,
116
132
*/
117
133
public function getBuiltinType (): string
118
134
{
119
- return $ this ->builtinType ;
135
+ $ internalType = $ this ->unwrapNullableType ($ this ->internalType );
136
+ $ internalType = $ this ->unwrapGenericType ($ internalType );
137
+
138
+ return $ internalType instanceof BuiltinType ? $ internalType ->getBuiltinType () : TypeInfoType::BUILTIN_TYPE_OBJECT ;
120
139
}
121
140
122
141
public function isNullable (): bool
123
142
{
124
- return $ this ->nullable ;
143
+ return $ this ->internalType -> isNullable () ;
125
144
}
126
145
127
146
/**
@@ -131,12 +150,22 @@ public function isNullable(): bool
131
150
*/
132
151
public function getClassName (): ?string
133
152
{
134
- return $ this ->class ;
153
+ $ internalType = $ this ->unwrapNullableType ($ this ->internalType );
154
+ $ internalType = $ this ->unwrapGenericType ($ internalType );
155
+
156
+ if (!$ internalType instanceof ObjectType) {
157
+ return null ;
158
+ }
159
+
160
+ return $ internalType ->getClassName ();
135
161
}
136
162
137
163
public function isCollection (): bool
138
164
{
139
- return $ this ->collection ;
165
+ $ internalType = $ this ->unwrapNullableType ($ this ->internalType );
166
+ $ internalType = $ this ->unwrapGenericType ($ internalType );
167
+
168
+ return $ internalType ->isCollection ;
140
169
}
141
170
142
171
/**
@@ -148,7 +177,22 @@ public function isCollection(): bool
148
177
*/
149
178
public function getCollectionKeyTypes (): array
150
179
{
151
- return $ this ->collectionKeyType ;
180
+ $ internalType = $ this ->unwrapNullableType ($ this ->internalType );
181
+
182
+ if (!$ internalType instanceof GenericType) {
183
+ return [];
184
+ }
185
+
186
+ if (null === ($ collectionKeyType = $ internalType ->getGenericTypes ()[0 ] ?? null )) {
187
+ return [];
188
+ }
189
+
190
+ $ collectionKeyType = $ this ->convertFromTypeInfoType ($ collectionKeyType );
191
+ if (!\is_array ($ collectionKeyType )) {
192
+ $ collectionKeyType = [$ collectionKeyType ];
193
+ }
194
+
195
+ return $ collectionKeyType ;
152
196
}
153
197
154
198
/**
@@ -160,6 +204,108 @@ public function getCollectionKeyTypes(): array
160
204
*/
161
205
public function getCollectionValueTypes (): array
162
206
{
163
- return $ this ->collectionValueType ;
207
+ $ internalType = $ this ->unwrapNullableType ($ this ->internalType );
208
+
209
+ if (!$ internalType instanceof GenericType) {
210
+ return [];
211
+ }
212
+
213
+ if (null === ($ collectionValueType = $ internalType ->getGenericTypes ()[1 ] ?? null )) {
214
+ return [];
215
+ }
216
+
217
+ $ collectionValueType = $ this ->convertFromTypeInfoType ($ collectionValueType );
218
+ if (!\is_array ($ collectionValueType )) {
219
+ $ collectionValueType = [$ collectionValueType ];
220
+ }
221
+
222
+ return $ collectionValueType ;
223
+ }
224
+
225
+ private function getTypeInfoType (): TypeInfoType
226
+ {
227
+ return $ this ->internalType ;
228
+ }
229
+
230
+ private function convertFromTypeInfoType (TypeInfoType $ typeInfoType ): self |array
231
+ {
232
+ if ($ typeInfoType instanceof UnionType) {
233
+ return array_map ($ this ->convertFromTypeInfoType (...), $ typeInfoType ->getTypes ());
234
+ }
235
+
236
+ if ($ typeInfoType instanceof IntersectionType) {
237
+ return array_map ($ this ->convertFromTypeInfoType (...), $ typeInfoType ->getTypes ());
238
+ }
239
+
240
+ $ builtinType = TypeInfoType::BUILTIN_TYPE_MIXED ;
241
+ $ className = null ;
242
+ $ collectionKeyType = $ collectionValueType = null ;
243
+
244
+ if ($ typeInfoType instanceof ObjectType) {
245
+ $ builtinType = TypeInfoType::BUILTIN_TYPE_OBJECT ;
246
+ $ className = $ typeInfoType ->getClassName ();
247
+ }
248
+
249
+ if ($ typeInfoType instanceof GenericType) {
250
+ /** @var BuiltinType $nestedType */
251
+ $ nestedType = $ this ->unwrapNullableType ($ typeInfoType ->getType ());
252
+ $ builtinType = $ nestedType ->getBuiltinType ();
253
+
254
+ $ genericTypes = $ typeInfoType ->getGenericTypes ();
255
+ $ collectionKeyType = isset ($ genericTypes [0 ]) ? $ this ->convertFromTypeInfoType ($ genericTypes [0 ]) : null ;
256
+ $ collectionValueType = isset ($ genericTypes [1 ]) ? $ this ->convertFromTypeInfoType ($ genericTypes [1 ]) : null ;
257
+ }
258
+
259
+ if ($ typeInfoType instanceof BuiltinType) {
260
+ $ builtinType = $ typeInfoType ->getBuiltinType ();
261
+ }
262
+
263
+ return new self (
264
+ builtinType: $ builtinType ,
265
+ nullable: $ typeInfoType ->isNullable (),
266
+ class: $ className ,
267
+ collection: $ typeInfoType ->isCollection ,
268
+ collectionKeyType: $ collectionKeyType ,
269
+ collectionValueType: $ collectionValueType ,
270
+ );
271
+ }
272
+
273
+ private function validateCollectionArgument (array |self |null $ collectionArgument , int $ argumentIndex , string $ argumentName ): ?array
274
+ {
275
+ if (null === $ collectionArgument ) {
276
+ return null ;
277
+ }
278
+
279
+ if (\is_array ($ collectionArgument )) {
280
+ foreach ($ collectionArgument as $ type ) {
281
+ if (!$ type instanceof self) {
282
+ 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 )));
283
+ }
284
+ }
285
+
286
+ return $ collectionArgument ;
287
+ }
288
+
289
+ return [$ collectionArgument ];
290
+ }
291
+
292
+ private function unwrapNullableType (TypeInfoType $ type ): TypeInfoType
293
+ {
294
+ if (!$ type instanceof UnionType) {
295
+ return $ type ;
296
+ }
297
+
298
+ $ unionTypes = $ type ->getTypes ();
299
+
300
+ return (string ) TypeInfoType::null () === (string ) $ unionTypes [0 ] ? $ unionTypes [1 ] : $ unionTypes [0 ];
301
+ }
302
+
303
+ private function unwrapGenericType (TypeInfoType $ type ): TypeInfoType
304
+ {
305
+ if (!$ type instanceof GenericType) {
306
+ return $ type ;
307
+ }
308
+
309
+ return $ type ->getType ();
164
310
}
165
311
}
0 commit comments