2424use Symfony \Component \PropertyInfo \PropertyAccessExtractorInterface ;
2525use Symfony \Component \PropertyInfo \PropertyListExtractorInterface ;
2626use 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 ;
2830
2931/**
3032 * Extracts data using Doctrine ORM and ODM metadata.
@@ -55,7 +57,7 @@ public function getProperties(string $class, array $context = []): ?array
5557 return $ properties ;
5658 }
5759
58- public function getTypes (string $ class , string $ property , array $ context = []): ?array
60+ public function getType (string $ class , string $ property , array $ context = []): ?Type
5961 {
6062 if (null === $ metadata = $ this ->getMetadata ($ class )) {
6163 return null ;
@@ -67,16 +69,17 @@ public function getTypes(string $class, string $property, array $context = []):
6769 if ($ metadata ->isSingleValuedAssociation ($ property )) {
6870 if ($ metadata instanceof ClassMetadata) {
6971 $ associationMapping = $ metadata ->getAssociationMapping ($ property );
70-
7172 $ nullable = $ this ->isAssociationNullable ($ associationMapping );
7273 } else {
7374 $ nullable = false ;
7475 }
7576
76- return [new Type (Type::BUILTIN_TYPE_OBJECT , $ nullable , $ class )];
77+ $ t = Type::object ($ class );
78+
79+ return $ nullable ? Type::nullable ($ t ) : $ t ;
7780 }
7881
79- $ collectionKeyType = Type:: BUILTIN_TYPE_INT ;
82+ $ collectionKeyType = TypeIdentifier:: INT ;
8083
8184 if ($ metadata instanceof ClassMetadata) {
8285 $ associationMapping = $ metadata ->getAssociationMapping ($ property );
@@ -110,55 +113,195 @@ public function getTypes(string $class, string $property, array $context = []):
110113 }
111114 }
112115
113- return [new Type (
114- Type::BUILTIN_TYPE_OBJECT ,
116+ return Type::collection (Type::object (Collection::class), Type::object ($ class ), Type::builtin ($ collectionKeyType ));
117+ }
118+
119+ if ($ metadata instanceof ClassMetadata && isset ($ metadata ->embeddedClasses [$ property ])) {
120+ return Type::object (self ::getMappingValue ($ metadata ->embeddedClasses [$ property ], 'class ' ));
121+ }
122+
123+ if ($ metadata ->hasField ($ property )) {
124+ $ typeOfField = $ metadata ->getTypeOfField ($ property );
125+
126+ if (!$ builtinType = $ this ->getPhpType ($ typeOfField )) {
127+ return null ;
128+ }
129+
130+ $ nullable = $ metadata instanceof ClassMetadata && $ metadata ->isNullable ($ property );
131+ $ enumType = null ;
132+ if (null !== $ enumClass = self ::getMappingValue ($ metadata ->getFieldMapping ($ property ), 'enumType ' ) ?? null ) {
133+ $ enumType = Type::enum ($ enumClass );
134+ $ enumType = $ nullable ? Type::nullable ($ enumType ) : $ enumType ;
135+ }
136+
137+ switch ($ builtinType ) {
138+ case TypeIdentifier::OBJECT :
139+ switch ($ typeOfField ) {
140+ case Types::DATE_MUTABLE :
141+ case Types::DATETIME_MUTABLE :
142+ case Types::DATETIMETZ_MUTABLE :
143+ case 'vardatetime ' :
144+ case Types::TIME_MUTABLE :
145+ $ t = Type::object (\DateTime::class);
146+
147+ return $ nullable ? Type::nullable ($ t ) : $ t ;
148+
149+ case Types::DATE_IMMUTABLE :
150+ case Types::DATETIME_IMMUTABLE :
151+ case Types::DATETIMETZ_IMMUTABLE :
152+ case Types::TIME_IMMUTABLE :
153+ $ t = Type::object (\DateTimeImmutable::class);
154+
155+ return $ nullable ? Type::nullable ($ t ) : $ t ;
156+
157+ case Types::DATEINTERVAL :
158+ $ t = Type::object (\DateInterval::class);
159+
160+ return $ nullable ? Type::nullable ($ t ) : $ t ;
161+ }
162+
163+ break ;
164+ case TypeIdentifier::ARRAY :
165+ switch ($ typeOfField ) {
166+ case 'array ' : // DBAL < 4
167+ case 'json_array ' : // DBAL < 3
168+ // return null if $enumType is set, because we can't determine if collectionKeyType is string or int
169+ if ($ enumType ) {
170+ return null ;
171+ }
172+
173+ $ t = Type::array ();
174+
175+ return $ nullable ? Type::nullable ($ t ) : $ t ;
176+
177+ case Types::SIMPLE_ARRAY :
178+ $ t = Type::list ($ enumType ?? Type::string ());
179+
180+ return $ nullable ? Type::nullable ($ t ) : $ t ;
181+ }
182+ break ;
183+ case TypeIdentifier::INT :
184+ case TypeIdentifier::STRING :
185+ if ($ enumType ) {
186+ return $ enumType ;
187+ }
188+ break ;
189+ }
190+
191+ $ t = Type::builtin ($ builtinType );
192+
193+ return $ nullable ? Type::nullable ($ t ) : $ t ;
194+ }
195+
196+ return null ;
197+ }
198+
199+ public function getTypes (string $ class , string $ property , array $ context = []): ?array
200+ {
201+ trigger_deprecation ('symfony/doctrine-bridge ' , '7.1 ' , 'The "%s()" method is deprecated, use "%s::getType()" instead. ' , __METHOD__ , self ::class);
202+
203+ if (null === $ metadata = $ this ->getMetadata ($ class )) {
204+ return null ;
205+ }
206+
207+ if ($ metadata ->hasAssociation ($ property )) {
208+ $ class = $ metadata ->getAssociationTargetClass ($ property );
209+
210+ if ($ metadata ->isSingleValuedAssociation ($ property )) {
211+ if ($ metadata instanceof ClassMetadata) {
212+ $ associationMapping = $ metadata ->getAssociationMapping ($ property );
213+
214+ $ nullable = $ this ->isAssociationNullable ($ associationMapping );
215+ } else {
216+ $ nullable = false ;
217+ }
218+
219+ return [new LegacyType (LegacyType::BUILTIN_TYPE_OBJECT , $ nullable , $ class )];
220+ }
221+
222+ $ collectionKeyType = LegacyType::BUILTIN_TYPE_INT ;
223+
224+ if ($ metadata instanceof ClassMetadata) {
225+ $ associationMapping = $ metadata ->getAssociationMapping ($ property );
226+
227+ if (isset ($ associationMapping ['indexBy ' ])) {
228+ $ subMetadata = $ this ->entityManager ->getClassMetadata ($ associationMapping ['targetEntity ' ]);
229+
230+ // Check if indexBy value is a property
231+ $ fieldName = $ associationMapping ['indexBy ' ];
232+ if (null === ($ typeOfField = $ subMetadata ->getTypeOfField ($ fieldName ))) {
233+ $ fieldName = $ subMetadata ->getFieldForColumn ($ associationMapping ['indexBy ' ]);
234+ // Not a property, maybe a column name?
235+ if (null === ($ typeOfField = $ subMetadata ->getTypeOfField ($ fieldName ))) {
236+ // Maybe the column name is the association join column?
237+ $ associationMapping = $ subMetadata ->getAssociationMapping ($ fieldName );
238+
239+ $ indexProperty = $ subMetadata ->getSingleAssociationReferencedJoinColumnName ($ fieldName );
240+ $ subMetadata = $ this ->entityManager ->getClassMetadata ($ associationMapping ['targetEntity ' ]);
241+
242+ // Not a property, maybe a column name?
243+ if (null === ($ typeOfField = $ subMetadata ->getTypeOfField ($ indexProperty ))) {
244+ $ fieldName = $ subMetadata ->getFieldForColumn ($ indexProperty );
245+ $ typeOfField = $ subMetadata ->getTypeOfField ($ fieldName );
246+ }
247+ }
248+ }
249+
250+ if (!$ collectionKeyType = $ this ->getPhpType ($ typeOfField )?->value) {
251+ return null ;
252+ }
253+ }
254+ }
255+
256+ return [new LegacyType (
257+ LegacyType::BUILTIN_TYPE_OBJECT ,
115258 false ,
116259 Collection::class,
117260 true ,
118- new Type ($ collectionKeyType ),
119- new Type (Type ::BUILTIN_TYPE_OBJECT , false , $ class )
261+ new LegacyType ($ collectionKeyType ),
262+ new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , false , $ class )
120263 )];
121264 }
122265
123266 if ($ metadata instanceof ClassMetadata && isset ($ metadata ->embeddedClasses [$ property ])) {
124- return [new Type (Type ::BUILTIN_TYPE_OBJECT , false , self :: getMappingValue ( $ metadata ->embeddedClasses [$ property ], 'class ' ) )];
267+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , false , $ metadata ->embeddedClasses [$ property ][ 'class ' ] )];
125268 }
126269
127270 if ($ metadata ->hasField ($ property )) {
128271 $ typeOfField = $ metadata ->getTypeOfField ($ property );
129272
130- if (!$ builtinType = $ this ->getPhpType ($ typeOfField )) {
273+ if (!$ builtinType = $ this ->getPhpType ($ typeOfField )?->value ) {
131274 return null ;
132275 }
133276
134277 $ nullable = $ metadata instanceof ClassMetadata && $ metadata ->isNullable ($ property );
135278 $ enumType = null ;
136- if (null !== $ enumClass = self :: getMappingValue ( $ metadata ->getFieldMapping ($ property ), 'enumType ' ) ?? null ) {
137- $ enumType = new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , $ enumClass );
279+ if (null !== $ enumClass = $ metadata ->getFieldMapping ($ property )[ 'enumType ' ] ?? null ) {
280+ $ enumType = new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , $ enumClass );
138281 }
139282
140283 switch ($ builtinType ) {
141- case Type ::BUILTIN_TYPE_OBJECT :
284+ case LegacyType ::BUILTIN_TYPE_OBJECT :
142285 switch ($ typeOfField ) {
143286 case Types::DATE_MUTABLE :
144287 case Types::DATETIME_MUTABLE :
145288 case Types::DATETIMETZ_MUTABLE :
146289 case 'vardatetime ' :
147290 case Types::TIME_MUTABLE :
148- return [new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTime ' )];
291+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTime ' )];
149292
150293 case Types::DATE_IMMUTABLE :
151294 case Types::DATETIME_IMMUTABLE :
152295 case Types::DATETIMETZ_IMMUTABLE :
153296 case Types::TIME_IMMUTABLE :
154- return [new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTimeImmutable ' )];
297+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateTimeImmutable ' )];
155298
156299 case Types::DATEINTERVAL :
157- return [new Type (Type ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateInterval ' )];
300+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_OBJECT , $ nullable , 'DateInterval ' )];
158301 }
159302
160303 break ;
161- case Type ::BUILTIN_TYPE_ARRAY :
304+ case LegacyType ::BUILTIN_TYPE_ARRAY :
162305 switch ($ typeOfField ) {
163306 case 'array ' : // DBAL < 4
164307 case 'json_array ' : // DBAL < 3
@@ -167,21 +310,21 @@ public function getTypes(string $class, string $property, array $context = []):
167310 return null ;
168311 }
169312
170- return [new Type (Type ::BUILTIN_TYPE_ARRAY , $ nullable , null , true )];
313+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_ARRAY , $ nullable , null , true )];
171314
172315 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 ))];
316+ return [new LegacyType (LegacyType ::BUILTIN_TYPE_ARRAY , $ nullable , null , true , new LegacyType (LegacyType ::BUILTIN_TYPE_INT ), $ enumType ?? new LegacyType (LegacyType ::BUILTIN_TYPE_STRING ))];
174317 }
175318 break ;
176- case Type ::BUILTIN_TYPE_INT :
177- case Type ::BUILTIN_TYPE_STRING :
319+ case LegacyType ::BUILTIN_TYPE_INT :
320+ case LegacyType ::BUILTIN_TYPE_STRING :
178321 if ($ enumType ) {
179322 return [$ enumType ];
180323 }
181324 break ;
182325 }
183326
184- return [new Type ($ builtinType , $ nullable )];
327+ return [new LegacyType ($ builtinType , $ nullable )];
185328 }
186329
187330 return null ;
@@ -244,20 +387,20 @@ private function isAssociationNullable(array|AssociationMapping $associationMapp
244387 /**
245388 * Gets the corresponding built-in PHP type.
246389 */
247- private function getPhpType (string $ doctrineType ): ?string
390+ private function getPhpType (string $ doctrineType ): ?TypeIdentifier
248391 {
249392 return match ($ doctrineType ) {
250393 Types::SMALLINT ,
251- Types::INTEGER => Type:: BUILTIN_TYPE_INT ,
252- Types::FLOAT => Type:: BUILTIN_TYPE_FLOAT ,
394+ Types::INTEGER => TypeIdentifier:: INT ,
395+ Types::FLOAT => TypeIdentifier:: FLOAT ,
253396 Types::BIGINT ,
254397 Types::STRING ,
255398 Types::TEXT ,
256399 Types::GUID ,
257- Types::DECIMAL => Type:: BUILTIN_TYPE_STRING ,
258- Types::BOOLEAN => Type:: BUILTIN_TYPE_BOOL ,
400+ Types::DECIMAL => TypeIdentifier:: STRING ,
401+ Types::BOOLEAN => TypeIdentifier:: BOOL ,
259402 Types::BLOB ,
260- Types::BINARY => Type:: BUILTIN_TYPE_RESOURCE ,
403+ Types::BINARY => TypeIdentifier:: RESOURCE ,
261404 'object ' , // DBAL < 4
262405 Types::DATE_MUTABLE ,
263406 Types::DATETIME_MUTABLE ,
@@ -268,10 +411,10 @@ private function getPhpType(string $doctrineType): ?string
268411 Types::DATETIME_IMMUTABLE ,
269412 Types::DATETIMETZ_IMMUTABLE ,
270413 Types::TIME_IMMUTABLE ,
271- Types::DATEINTERVAL => Type:: BUILTIN_TYPE_OBJECT ,
414+ Types::DATEINTERVAL => TypeIdentifier:: OBJECT ,
272415 'array ' , // DBAL < 4
273416 'json_array ' , // DBAL < 3
274- Types::SIMPLE_ARRAY => Type:: BUILTIN_TYPE_ARRAY ,
417+ Types::SIMPLE_ARRAY => TypeIdentifier:: ARRAY ,
275418 default => null ,
276419 };
277420 }
0 commit comments