|
13 | 13 |
|
14 | 14 | namespace CodeIgniter\PHPStan\Type; |
15 | 15 |
|
| 16 | +use CodeIgniter\PHPStan\Database\Schema\CastTypeResolver; |
| 17 | +use CodeIgniter\PHPStan\Database\Schema\Column; |
16 | 18 | use CodeIgniter\PHPStan\Database\Schema\ColumnTypeResolver; |
17 | 19 | use CodeIgniter\PHPStan\Database\SchemaProvider; |
18 | 20 | use CodeIgniter\PHPStan\NodeVisitor\ModelReturnTypeTransformVisitor; |
|
33 | 35 |
|
34 | 36 | /** |
35 | 37 | * Resolves the type of a single fetched row for a model, honoring its `$returnType` (or the |
36 | | - * `asArray()`/`asObject()` override) and shaping array rows from the live table columns. |
| 38 | + * `asArray()`/`asObject()` override) and shaping array rows from the live columns and `$casts`. |
37 | 39 | */ |
38 | 40 | final class ModelFetchedReturnTypeHelper |
39 | 41 | { |
40 | 42 | public function __construct( |
41 | 43 | private readonly ReflectionProvider $reflectionProvider, |
42 | 44 | private readonly SchemaProvider $schemaProvider, |
43 | 45 | private readonly ColumnTypeResolver $columnTypeResolver, |
| 46 | + private readonly CastTypeResolver $castTypeResolver, |
44 | 47 | ) {} |
45 | 48 |
|
46 | 49 | public function getFetchedReturnType(ClassReflection $classReflection, ?MethodCall $methodCall, Scope $scope): Type |
@@ -91,12 +94,47 @@ private function resolveArrayRowType(ClassReflection $classReflection): Type |
91 | 94 | return new ArrayType(new StringType(), new MixedType()); |
92 | 95 | } |
93 | 96 |
|
| 97 | + $casts = $this->readStringMap($classReflection, 'casts'); |
94 | 98 | $builder = ConstantArrayTypeBuilder::createEmpty(); |
95 | 99 |
|
96 | 100 | foreach ($table->columns as $column) { |
97 | | - $builder->setOffsetValueType(new ConstantStringType($column->name), $this->columnTypeResolver->resolve($column)); |
| 101 | + $builder->setOffsetValueType(new ConstantStringType($column->name), $this->resolveFieldType($column, $casts)); |
98 | 102 | } |
99 | 103 |
|
100 | 104 | return $builder->getArray(); |
101 | 105 | } |
| 106 | + |
| 107 | + /** |
| 108 | + * @param array<string, string> $casts |
| 109 | + */ |
| 110 | + private function resolveFieldType(Column $column, array $casts): Type |
| 111 | + { |
| 112 | + if (isset($casts[$column->name])) { |
| 113 | + return $this->castTypeResolver->resolve($casts[$column->name]) ?? new MixedType(); |
| 114 | + } |
| 115 | + |
| 116 | + return $this->columnTypeResolver->resolve($column); |
| 117 | + } |
| 118 | + |
| 119 | + /** |
| 120 | + * @return array<string, string> |
| 121 | + */ |
| 122 | + private function readStringMap(ClassReflection $classReflection, string $property): array |
| 123 | + { |
| 124 | + $value = $classReflection->getNativeReflection()->getDefaultProperties()[$property] ?? []; |
| 125 | + |
| 126 | + if (! is_array($value)) { |
| 127 | + return []; |
| 128 | + } |
| 129 | + |
| 130 | + $map = []; |
| 131 | + |
| 132 | + foreach ($value as $key => $cast) { |
| 133 | + if (is_string($key) && is_string($cast)) { |
| 134 | + $map[$key] = $cast; |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + return $map; |
| 139 | + } |
102 | 140 | } |
0 commit comments