2727use PHPStan \Type \Constant \ConstantArrayTypeBuilder ;
2828use PHPStan \Type \Constant \ConstantStringType ;
2929use PHPStan \Type \MixedType ;
30+ use PHPStan \Type \ObjectShapeType ;
3031use PHPStan \Type \ObjectType ;
3132use PHPStan \Type \ObjectWithoutClassType ;
3233use PHPStan \Type \StringType ;
@@ -51,7 +52,7 @@ public function getFetchedReturnType(ClassReflection $classReflection, ?MethodCa
5152 $ returnType = $ this ->resolveReturnType ($ classReflection , $ methodCall , $ scope );
5253
5354 if ($ returnType === 'object ' ) {
54- return new ObjectType (stdClass::class );
55+ return $ this -> resolveObjectRowType ( $ classReflection );
5556 }
5657
5758 if ($ returnType === 'array ' ) {
@@ -85,24 +86,55 @@ private function resolveReturnType(ClassReflection $classReflection, ?MethodCall
8586 }
8687
8788 private function resolveArrayRowType (ClassReflection $ classReflection ): Type
89+ {
90+ $ fields = $ this ->resolveRowFieldTypes ($ classReflection );
91+
92+ if ($ fields === null ) {
93+ return new ArrayType (new StringType (), new MixedType ());
94+ }
95+
96+ $ builder = ConstantArrayTypeBuilder::createEmpty ();
97+
98+ foreach ($ fields as $ name => $ type ) {
99+ $ builder ->setOffsetValueType (new ConstantStringType ($ name ), $ type );
100+ }
101+
102+ return $ builder ->getArray ();
103+ }
104+
105+ private function resolveObjectRowType (ClassReflection $ classReflection ): Type
106+ {
107+ $ fields = $ this ->resolveRowFieldTypes ($ classReflection );
108+
109+ if ($ fields === null ) {
110+ return new ObjectType (stdClass::class);
111+ }
112+
113+ return new ObjectShapeType ($ fields , []);
114+ }
115+
116+ /**
117+ * @return array<string, Type>|null Null when the model's table cannot be resolved.
118+ */
119+ private function resolveRowFieldTypes (ClassReflection $ classReflection ): ?array
88120 {
89121 $ tableName = $ classReflection ->getNativeReflection ()->getDefaultProperties ()['table ' ] ?? null ;
90122
91123 $ table = is_string ($ tableName ) && $ tableName !== '' ? $ this ->schemaProvider ->get ()->getTable ($ tableName ) : null ;
92124
93125 if ($ table === null ) {
94- return new ArrayType ( new StringType (), new MixedType ()) ;
126+ return null ;
95127 }
96128
97129 $ casts = $ this ->readStringMap ($ classReflection , 'casts ' );
98130 $ castHandlers = $ this ->readStringMap ($ classReflection , 'castHandlers ' );
99- $ builder = ConstantArrayTypeBuilder:: createEmpty () ;
131+ $ fields = [] ;
100132
101133 foreach ($ table ->columns as $ column ) {
102- $ builder -> setOffsetValueType ( new ConstantStringType ( $ column ->name ), $ this ->resolveFieldType ($ column , $ casts , $ castHandlers) );
134+ $ fields [ $ column ->name ] = $ this ->resolveFieldType ($ column , $ casts , $ castHandlers );
103135 }
104136
105- return $ builder -> getArray () ;
137+ return $ fields ;
106138 }
107139
108140 /**
0 commit comments