24
24
use Symfony \Component \PropertyInfo \PropertyAccessExtractorInterface ;
25
25
use Symfony \Component \PropertyInfo \PropertyListExtractorInterface ;
26
26
use Symfony \Component \PropertyInfo \PropertyTypeExtractorInterface ;
27
- use Symfony \Component \PropertyInfo \Type ;
27
+ use Symfony \Component \PropertyInfo \Type as LegacyType ;
28
+ use Symfony \Component \TypeInfo \Type ;
29
+ use Symfony \Component \TypeInfo \TypeIdentifier ;
28
30
29
31
/**
30
32
* Extracts data using Doctrine ORM and ODM metadata.
@@ -55,8 +57,110 @@ public function getProperties(string $class, array $context = []): ?array
55
57
return $ properties ;
56
58
}
57
59
60
+ public function getType (string $ class , string $ property , array $ context = []): ?Type
61
+ {
62
+ if (null === $ metadata = $ this ->getMetadata ($ class )) {
63
+ return null ;
64
+ }
65
+
66
+ if ($ metadata ->hasAssociation ($ property )) {
67
+ $ class = $ metadata ->getAssociationTargetClass ($ property );
68
+
69
+ if ($ metadata ->isSingleValuedAssociation ($ property )) {
70
+ if ($ metadata instanceof ClassMetadata) {
71
+ $ associationMapping = $ metadata ->getAssociationMapping ($ property );
72
+ $ nullable = $ this ->isAssociationNullable ($ associationMapping );
73
+ } else {
74
+ $ nullable = false ;
75
+ }
76
+
77
+ return $ nullable ? Type::nullable (Type::object ($ class )) : Type::object ($ class );
78
+ }
79
+
80
+ $ collectionKeyType = TypeIdentifier::INT ;
81
+
82
+ if ($ metadata instanceof ClassMetadata) {
83
+ $ associationMapping = $ metadata ->getAssociationMapping ($ property );
84
+
85
+ if (self ::getMappingValue ($ associationMapping , 'indexBy ' )) {
86
+ $ subMetadata = $ this ->entityManager ->getClassMetadata (self ::getMappingValue ($ associationMapping , 'targetEntity ' ));
87
+
88
+ // Check if indexBy value is a property
89
+ $ fieldName = self ::getMappingValue ($ associationMapping , 'indexBy ' );
90
+ if (null === ($ typeOfField = $ subMetadata ->getTypeOfField ($ fieldName ))) {
91
+ $ fieldName = $ subMetadata ->getFieldForColumn (self ::getMappingValue ($ associationMapping , 'indexBy ' ));
92
+ // Not a property, maybe a column name?
93
+ if (null === ($ typeOfField = $ subMetadata ->getTypeOfField ($ fieldName ))) {
94
+ // Maybe the column name is the association join column?
95
+ $ associationMapping = $ subMetadata ->getAssociationMapping ($ fieldName );
96
+
97
+ $ indexProperty = $ subMetadata ->getSingleAssociationReferencedJoinColumnName ($ fieldName );
98
+ $ subMetadata = $ this ->entityManager ->getClassMetadata (self ::getMappingValue ($ associationMapping , 'targetEntity ' ));
99
+
100
+ // Not a property, maybe a column name?
101
+ if (null === ($ typeOfField = $ subMetadata ->getTypeOfField ($ indexProperty ))) {
102
+ $ fieldName = $ subMetadata ->getFieldForColumn ($ indexProperty );
103
+ $ typeOfField = $ subMetadata ->getTypeOfField ($ fieldName );
104
+ }
105
+ }
106
+ }
107
+
108
+ if (!$ collectionKeyType = $ this ->getTypeIdentifier ($ typeOfField )) {
109
+ return null ;
110
+ }
111
+ }
112
+ }
113
+
114
+ return Type::collection (Type::object (Collection::class), Type::object ($ class ), Type::builtin ($ collectionKeyType ));
115
+ }
116
+
117
+ if ($ metadata instanceof ClassMetadata && isset ($ metadata ->embeddedClasses [$ property ])) {
118
+ return Type::object (self ::getMappingValue ($ metadata ->embeddedClasses [$ property ], 'class ' ));
119
+ }
120
+
121
+ if (!$ metadata ->hasField ($ property )) {
122
+ return null ;
123
+ }
124
+
125
+ $ typeOfField = $ metadata ->getTypeOfField ($ property );
126
+
127
+ if (!$ typeIdentifier = $ this ->getTypeIdentifier ($ typeOfField )) {
128
+ return null ;
129
+ }
130
+
131
+ $ nullable = $ metadata instanceof ClassMetadata && $ metadata ->isNullable ($ property );
132
+ $ enumType = null ;
133
+
134
+ if (null !== $ enumClass = self ::getMappingValue ($ metadata ->getFieldMapping ($ property ), 'enumType ' ) ?? null ) {
135
+ $ enumType = $ nullable ? Type::nullable (Type::enum ($ enumClass )) : Type::enum ($ enumClass );
136
+ }
137
+
138
+ $ builtinType = $ nullable ? Type::nullable (Type::builtin ($ typeIdentifier )) : Type::builtin ($ typeIdentifier );
139
+
140
+ return match ($ typeIdentifier ) {
141
+ TypeIdentifier::OBJECT => match ($ typeOfField ) {
142
+ Types::DATE_MUTABLE , Types::DATETIME_MUTABLE , Types::DATETIMETZ_MUTABLE , 'vardatetime ' , Types::TIME_MUTABLE => $ nullable ? Type::nullable (Type::object (\DateTime::class)) : Type::object (\DateTime::class),
143
+ Types::DATE_IMMUTABLE , Types::DATETIME_IMMUTABLE , Types::DATETIMETZ_IMMUTABLE , Types::TIME_IMMUTABLE => $ nullable ? Type::nullable (Type::object (\DateTimeImmutable::class)) : Type::object (\DateTimeImmutable::class),
144
+ Types::DATEINTERVAL => $ nullable ? Type::nullable (Type::object (\DateInterval::class)) : Type::object (\DateInterval::class),
145
+ default => $ builtinType ,
146
+ },
147
+ TypeIdentifier::ARRAY => match ($ typeOfField ) {
148
+ 'array ' , 'json_array ' => $ enumType ? null : ($ nullable ? Type::nullable (Type::array ()) : Type::array ()),
149
+ Types::SIMPLE_ARRAY => $ nullable ? Type::nullable (Type::list ($ enumType ?? Type::string ())) : Type::list ($ enumType ?? Type::string ()),
150
+ default => $ builtinType ,
151
+ },
152
+ TypeIdentifier::INT , TypeIdentifier::STRING => $ enumType ? $ enumType : $ builtinType ,
153
+ default => $ builtinType ,
154
+ };
155
+ }
156
+
157
+ /**
158
+ * @deprecated since Symfony 7.1, use "getType" instead
159
+ */
58
160
public function getTypes (string $ class , string $ property , array $ context = []): ?array
59
161
{
162
+ trigger_deprecation ('symfony/property-info ' , '7.1 ' , 'The "%s()" method is deprecated, use "%s::getType()" instead. ' , __METHOD__ , self ::class);
163
+
60
164
if (null === $ metadata = $ this ->getMetadata ($ class )) {
61
165
return null ;
62
166
}
@@ -73,10 +177,10 @@ public function getTypes(string $class, string $property, array $context = []):
73
177
$ nullable = false ;
74
178
}
75
179
76
- return [new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , $ class )];
180
+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , $ class )];
77
181
}
78
182
79
- $ collectionKeyType = Type ::BUILTIN_TYPE_INT ;
183
+ $ collectionKeyType = LegacyType ::BUILTIN_TYPE_INT ;
80
184
81
185
if ($ metadata instanceof ClassMetadata) {
82
186
$ associationMapping = $ metadata ->getAssociationMapping ($ property );
@@ -104,61 +208,61 @@ public function getTypes(string $class, string $property, array $context = []):
104
208
}
105
209
}
106
210
107
- if (!$ collectionKeyType = $ this ->getPhpType ($ typeOfField )) {
211
+ if (!$ collectionKeyType = $ this ->getTypeIdentifier ($ typeOfField )?->value ) {
108
212
return null ;
109
213
}
110
214
}
111
215
}
112
216
113
- return [new Type (
114
- Type ::BUILTIN_TYPE_OBJECT ,
217
+ return [new LegacyType (
218
+ LegacyType ::BUILTIN_TYPE_OBJECT ,
115
219
false ,
116
220
Collection::class,
117
221
true ,
118
- new Type ($ collectionKeyType ),
119
- new Type (Type ::BUILTIN_TYPE_OBJECT , false , $ class )
222
+ new LegacyType ($ collectionKeyType ),
223
+ new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , false , $ class )
120
224
)];
121
225
}
122
226
123
227
if ($ metadata instanceof ClassMetadata && isset ($ metadata ->embeddedClasses [$ property ])) {
124
- return [new Type (Type ::BUILTIN_TYPE_OBJECT , false , self ::getMappingValue ($ metadata ->embeddedClasses [$ property ], 'class ' ))];
228
+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , false , self ::getMappingValue ($ metadata ->embeddedClasses [$ property ], 'class ' ))];
125
229
}
126
230
127
231
if ($ metadata ->hasField ($ property )) {
128
232
$ typeOfField = $ metadata ->getTypeOfField ($ property );
129
233
130
- if (!$ builtinType = $ this ->getPhpType ($ typeOfField )) {
234
+ if (!$ builtinType = $ this ->getTypeIdentifier ($ typeOfField )?->value ) {
131
235
return null ;
132
236
}
133
237
134
238
$ nullable = $ metadata instanceof ClassMetadata && $ metadata ->isNullable ($ property );
135
239
$ enumType = null ;
136
240
if (null !== $ enumClass = self ::getMappingValue ($ metadata ->getFieldMapping ($ property ), 'enumType ' ) ?? null ) {
137
- $ enumType = new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , $ enumClass );
241
+ $ enumType = new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , $ enumClass );
138
242
}
139
243
140
244
switch ($ builtinType ) {
141
- case Type ::BUILTIN_TYPE_OBJECT :
245
+ case LegacyType ::BUILTIN_TYPE_OBJECT :
142
246
switch ($ typeOfField ) {
143
247
case Types::DATE_MUTABLE :
144
248
case Types::DATETIME_MUTABLE :
145
249
case Types::DATETIMETZ_MUTABLE :
146
250
case 'vardatetime ' :
147
251
case Types::TIME_MUTABLE :
148
- return [new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTime ' )];
252
+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTime ' )];
149
253
150
254
case Types::DATE_IMMUTABLE :
151
255
case Types::DATETIME_IMMUTABLE :
152
256
case Types::DATETIMETZ_IMMUTABLE :
153
257
case Types::TIME_IMMUTABLE :
154
- return [new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTimeImmutable ' )];
258
+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTimeImmutable ' )];
155
259
156
260
case Types::DATEINTERVAL :
157
- return [new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateInterval ' )];
261
+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateInterval ' )];
158
262
}
159
263
160
264
break ;
161
- case Type ::BUILTIN_TYPE_ARRAY :
265
+ case LegacyType ::BUILTIN_TYPE_ARRAY :
162
266
switch ($ typeOfField ) {
163
267
case 'array ' : // DBAL < 4
164
268
case 'json_array ' : // DBAL < 3
@@ -167,21 +271,21 @@ public function getTypes(string $class, string $property, array $context = []):
167
271
return null ;
168
272
}
169
273
170
- return [new Type (Type ::BUILTIN_TYPE_ARRAY , $ nullable , null , true )];
274
+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_ARRAY , $ nullable , null , true )];
171
275
172
276
case Types::SIMPLE_ARRAY :
173
- return [new Type (Type ::BUILTIN_TYPE_ARRAY , $ nullable , null , true , new Type (Type ::BUILTIN_TYPE_INT ), $ enumType ?? new Type (Type ::BUILTIN_TYPE_STRING ))];
277
+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_ARRAY , $ nullable , null , true , new LegacyType (LegacyType ::BUILTIN_TYPE_INT ), $ enumType ?? new LegacyType (LegacyType ::BUILTIN_TYPE_STRING ))];
174
278
}
175
279
break ;
176
- case Type ::BUILTIN_TYPE_INT :
177
- case Type ::BUILTIN_TYPE_STRING :
280
+ case LegacyType ::BUILTIN_TYPE_INT :
281
+ case LegacyType ::BUILTIN_TYPE_STRING :
178
282
if ($ enumType ) {
179
283
return [$ enumType ];
180
284
}
181
285
break ;
182
286
}
183
287
184
- return [new Type ($ builtinType , $ nullable )];
288
+ return [new LegacyType ($ builtinType , $ nullable )];
185
289
}
186
290
187
291
return null ;
@@ -244,20 +348,20 @@ private function isAssociationNullable(array|AssociationMapping $associationMapp
244
348
/**
245
349
* Gets the corresponding built-in PHP type.
246
350
*/
247
- private function getPhpType (string $ doctrineType ): ?string
351
+ private function getTypeIdentifier (string $ doctrineType ): ?TypeIdentifier
248
352
{
249
353
return match ($ doctrineType ) {
250
354
Types::SMALLINT ,
251
- Types::INTEGER => Type:: BUILTIN_TYPE_INT ,
252
- Types::FLOAT => Type:: BUILTIN_TYPE_FLOAT ,
355
+ Types::INTEGER => TypeIdentifier:: INT ,
356
+ Types::FLOAT => TypeIdentifier:: FLOAT ,
253
357
Types::BIGINT ,
254
358
Types::STRING ,
255
359
Types::TEXT ,
256
360
Types::GUID ,
257
- Types::DECIMAL => Type:: BUILTIN_TYPE_STRING ,
258
- Types::BOOLEAN => Type:: BUILTIN_TYPE_BOOL ,
361
+ Types::DECIMAL => TypeIdentifier:: STRING ,
362
+ Types::BOOLEAN => TypeIdentifier:: BOOL ,
259
363
Types::BLOB ,
260
- Types::BINARY => Type:: BUILTIN_TYPE_RESOURCE ,
364
+ Types::BINARY => TypeIdentifier:: RESOURCE ,
261
365
'object ' , // DBAL < 4
262
366
Types::DATE_MUTABLE ,
263
367
Types::DATETIME_MUTABLE ,
@@ -268,10 +372,10 @@ private function getPhpType(string $doctrineType): ?string
268
372
Types::DATETIME_IMMUTABLE ,
269
373
Types::DATETIMETZ_IMMUTABLE ,
270
374
Types::TIME_IMMUTABLE ,
271
- Types::DATEINTERVAL => Type:: BUILTIN_TYPE_OBJECT ,
375
+ Types::DATEINTERVAL => TypeIdentifier:: OBJECT ,
272
376
'array ' , // DBAL < 4
273
377
'json_array ' , // DBAL < 3
274
- Types::SIMPLE_ARRAY => Type:: BUILTIN_TYPE_ARRAY ,
378
+ Types::SIMPLE_ARRAY => TypeIdentifier:: ARRAY ,
275
379
default => null ,
276
380
};
277
381
}
0 commit comments