66
77use Spiral \JsonSchemaGenerator \Exception \GeneratorException ;
88use Spiral \JsonSchemaGenerator \Exception \InvalidTypeException ;
9- use Spiral \JsonSchemaGenerator \Schema \Type as SchemaType ;
109use Symfony \Component \PropertyInfo \Extractor \PhpDocExtractor ;
1110use Symfony \Component \PropertyInfo \Extractor \PhpStanExtractor ;
1211use Symfony \Component \PropertyInfo \Extractor \ReflectionExtractor ;
1312use Symfony \Component \PropertyInfo \PropertyInfoExtractor ;
14- use Symfony \Component \PropertyInfo \PropertyInfoExtractorInterface ;
15- use Symfony \Component \PropertyInfo \Type as PropertyInfoType ;
13+ use Symfony \Component \PropertyInfo \PropertyTypeExtractorInterface ;
14+ use Symfony \Component \TypeInfo \Type \BackedEnumType ;
15+ use Symfony \Component \TypeInfo \Type \BuiltinType ;
16+ use Symfony \Component \TypeInfo \Type \CollectionType ;
17+ use Symfony \Component \TypeInfo \Type \ObjectType ;
18+ use Symfony \Component \TypeInfo \Type \UnionType ;
19+ use Symfony \Component \TypeInfo \TypeIdentifier ;
20+ use Symfony \Component \TypeInfo \Type as TypeInfoType ;
1621
1722/**
1823 * @internal
@@ -26,7 +31,7 @@ final class ClassParser implements ClassParserInterface
2631 */
2732 private array $ constructorParameters = [];
2833
29- private readonly PropertyInfoExtractorInterface $ propertyInfo ;
34+ private readonly PropertyTypeExtractorInterface $ propertyInfo ;
3035
3136 /**
3237 * @param \ReflectionClass|class-string $class
@@ -125,101 +130,74 @@ private function getEnumValues(string $typeName): ?array
125130 );
126131 }
127132
128- /**
129- * @param non-empty-string $typeName
130- */
131- private function getTypeBuildIn (string $ typeName ): bool
132- {
133- if ((\class_exists ($ typeName ))) {
134- return \is_subclass_of ($ typeName , \BackedEnum::class);
135- }
136-
137- return $ typeName !== SchemaType::Object->value ;
138- }
139-
140- /**
141- * @param non-empty-string|class-string $typeName
142- *
143- * @return non-empty-string|class-string
144- */
145- private function getEnumTypeName (string $ typeName ): string
133+ private function getPropertyType (\ReflectionProperty $ property ): Type
146134 {
147- if (!\is_subclass_of ($ typeName , \BackedEnum::class)) {
148- return $ typeName ;
149- }
135+ $ type = $ this ->propertyInfo ->getType ($ property ->class , $ property ->getName ());
150136
151- $ reflection = new \ReflectionEnum ($ typeName );
152- $ backingType = $ reflection ->getBackingType ();
153-
154- if (!$ backingType instanceof \ReflectionNamedType) {
155- return $ typeName ;
137+ if ($ type === null ) {
138+ throw new InvalidTypeException ();
156139 }
157140
158- return $ backingType -> getName ( );
141+ return $ this -> createType ( $ type );
159142 }
160143
161- private function getPropertyType ( \ ReflectionProperty $ property ): Type
144+ private function createType ( TypeInfoType $ type ): Type
162145 {
163- /** @psalm-suppress DeprecatedMethod, DeprecatedClass */
164- $ types = $ this ->propertyInfo ->getTypes ($ property ->class , $ property ->getName ());
165-
166146 $ simpleTypes = [];
167- $ isNullable = false ;
168- foreach ($ types ?? [] as $ type ) {
169- $ typeName = $ type ->getBuiltinType () === SchemaType::Object->value && $ type ->getClassName () !== null
170- ? $ type ->getClassName ()
171- : $ type ->getBuiltinType ();
172-
173- if ($ typeName === '' ) {
174- throw new InvalidTypeException ();
147+ if ($ type instanceof UnionType) {
148+ foreach ($ type ->getTypes () as $ subType ) {
149+ $ simpleType = $ this ->createSimpleType ($ subType );
150+ if ($ simpleType !== null ) {
151+ $ simpleTypes [] = $ simpleType ;
152+ }
175153 }
176- if ($ type ->isNullable () && $ isNullable === false ) {
177- $ simpleTypes [] = new SimpleType (
178- name: SchemaType::Null->value ,
179- builtin: true ,
180- );
181- $ isNullable = true ;
154+ } else {
155+ $ simpleType = $ this ->createSimpleType ($ type );
156+ if ($ simpleType !== null ) {
157+ $ simpleTypes [] = $ simpleType ;
182158 }
183-
184- $ simpleTypes [] = new SimpleType (
185- name: $ this ->getEnumTypeName ($ typeName ),
186- builtin: $ this ->getTypeBuildIn ($ typeName ),
187- collectionType: $ this ->getCollectionValueType ($ type ),
188- enum: $ this ->getEnumValues ($ typeName ),
189- );
190159 }
191160
192161 return new Type (types: $ simpleTypes );
193162 }
194163
195- /**
196- * @psalm-suppress DeprecatedClass
197- */
198- private function getCollectionValueType (PropertyInfoType $ propertyInfoType ): ?Type
164+ private function createSimpleType (TypeInfoType $ type ): ?SimpleType
199165 {
200- if (!$ propertyInfoType ->isCollection ()) {
201- return null ;
166+ $ typeName = '' ;
167+ $ builtin = true ;
168+ $ enum = null ;
169+ $ collectionType = null ;
170+ if ($ type instanceof BuiltinType) {
171+ if ($ type ->getTypeIdentifier () === TypeIdentifier::MIXED ) {
172+ return null ;
173+ }
174+ $ typeName = $ type ->getTypeIdentifier ()->value ;
175+ }
176+ if ($ type instanceof CollectionType) {
177+ $ typeName = TypeIdentifier::ARRAY ->value ;
178+ $ collectionType = $ this ->createType ($ type ->getCollectionValueType ());
179+ }
180+ if ($ type instanceof ObjectType) {
181+ $ typeName = $ type ->getClassName ();
182+ $ builtin = false ;
202183 }
203184
204- $ simpleTypes = [];
205- /** @psalm-suppress DeprecatedClass */
206- foreach ($ propertyInfoType ->getCollectionValueTypes () as $ collectionValueType ) {
207- $ typeName = $ collectionValueType ->getBuiltinType () === SchemaType::Object->value && $ collectionValueType ->getClassName () !== null
208- ? $ collectionValueType ->getClassName ()
209- : $ collectionValueType ->getBuiltinType ();
210-
211- if ($ typeName === '' ) {
212- throw new InvalidTypeException ();
213- }
185+ if ($ type instanceof BackedEnumType) {
186+ $ enum = $ this ->getEnumValues ($ type ->getClassName ());
187+ $ typeName = $ type ->getBackingType ()->getTypeIdentifier ()->value ;
188+ $ builtin = true ;
189+ }
214190
215- $ simpleTypes [] = new SimpleType (
216- name: $ this ->getEnumTypeName ($ typeName ),
217- builtin: $ this ->getTypeBuildIn ($ typeName ),
218- enum: $ this ->getEnumValues ($ typeName ),
219- );
191+ if ($ typeName === '' ) {
192+ throw new InvalidTypeException ();
220193 }
221194
222- return new Type (types: $ simpleTypes );
195+ return new SimpleType (
196+ name: $ typeName ,
197+ builtin: $ builtin ,
198+ collectionType: $ collectionType ,
199+ enum: $ enum ,
200+ );
223201 }
224202
225203 private function hasPropertyDefaultValue (\ReflectionProperty $ property ): bool
@@ -243,7 +221,7 @@ private function getPropertyDefaultValue(\ReflectionProperty $property): mixed
243221 return $ default ?? null ;
244222 }
245223
246- private function createPropertyInfo (): PropertyInfoExtractorInterface
224+ private function createPropertyInfo (): PropertyTypeExtractorInterface
247225 {
248226 return new PropertyInfoExtractor (typeExtractors: [
249227 new PhpStanExtractor (),
0 commit comments