Skip to content

Commit 1540223

Browse files
hembergerstaabm
andauthored
DoctrineKeyValueStyeRule: allow int values in float columns (#581)
Co-authored-by: Markus Staab <[email protected]>
1 parent 7526446 commit 1540223

File tree

5 files changed

+2020
-24
lines changed

5 files changed

+2020
-24
lines changed

src/Rules/DoctrineKeyValueStyleRule.php

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
use PHPStan\Type\IntegerRangeType;
1818
use PHPStan\Type\IntegerType;
1919
use PHPStan\Type\ObjectType;
20+
use PHPStan\Type\Type;
2021
use PHPStan\Type\TypeCombinator;
21-
use PHPStan\Type\UnionType;
2222
use PHPStan\Type\VerbosityLevel;
2323
use staabm\PHPStanDba\QueryReflection\QueryReflection;
2424

@@ -123,8 +123,6 @@ public function processNode(Node $callLike, Scope $scope): array
123123
}
124124
$schemaReflection = $this->queryReflection->getSchemaReflection();
125125

126-
$checkIntegerRanges = QueryReflection::getRuntimeConfiguration()->isParameterTypeValidationStrict();
127-
128126
$errors = [];
129127
foreach ($tableNames as $tableName) {
130128
// Table name may be escaped with backticks
@@ -173,29 +171,11 @@ public function processNode(Node $callLike, Scope $scope): array
173171
continue;
174172
}
175173

176-
$argColumnType = $argColumn->getType();
174+
$acceptingType = $this->getColumnAcceptingType($argColumn->getType());
177175
$valueType = $argArray->getValueTypes()[$keyIndex];
178176

179-
if (false === $checkIntegerRanges) {
180-
// Convert IntegerRangeType column types into IntegerType so
181-
// that any integer value is accepted for integer columns,
182-
// since it is uncommon to check integer value ranges.
183-
if ($argColumnType instanceof IntegerRangeType) {
184-
$argColumnType = new IntegerType();
185-
} elseif ($argColumnType instanceof UnionType) {
186-
$newTypes = [];
187-
foreach ($argColumnType->getTypes() as $type) {
188-
if ($type instanceof IntegerRangeType) {
189-
$type = new IntegerType();
190-
}
191-
$newTypes[] = $type;
192-
}
193-
$argColumnType = TypeCombinator::union(...$newTypes);
194-
}
195-
}
196-
197-
if (! $argColumnType->isSuperTypeOf($valueType)->yes()) {
198-
$errors[] = 'Column "' . $table->getName() . '.' . $argColumnName . '" expects value type ' . $argColumnType->describe(VerbosityLevel::precise()) . ', got type ' . $valueType->describe(VerbosityLevel::precise());
177+
if (! $acceptingType->isSuperTypeOf($valueType)->yes()) {
178+
$errors[] = 'Column "' . $table->getName() . '.' . $argColumnName . '" expects value type ' . $acceptingType->describe(VerbosityLevel::precise()) . ', got type ' . $valueType->describe(VerbosityLevel::precise());
199179
}
200180
}
201181
}
@@ -209,4 +189,33 @@ public function processNode(Node $callLike, Scope $scope): array
209189
}
210190
return $ruleErrors;
211191
}
192+
193+
/**
194+
* Converts the column type into the most general type that the column
195+
* will accept.
196+
*/
197+
private function getColumnAcceptingType(Type $columnType): Type
198+
{
199+
$checkIntegerRanges = QueryReflection::getRuntimeConfiguration()->isParameterTypeValidationStrict();
200+
if (false === $checkIntegerRanges) {
201+
// Convert IntegerRangeType column types into IntegerType so
202+
// that any integer value is accepted for integer columns,
203+
// since it is uncommon to check integer value ranges.
204+
$containedNull = TypeCombinator::containsNull($columnType);
205+
$columnType = TypeCombinator::removeNull($columnType);
206+
if ($columnType instanceof IntegerRangeType) {
207+
$columnType = new IntegerType();
208+
}
209+
if ($containedNull) {
210+
$columnType = TypeCombinator::addNull($columnType);
211+
}
212+
}
213+
214+
if ($columnType->isFloat()->yes()) {
215+
// Float column should also accept integer values
216+
$columnType = TypeCombinator::union(new IntegerType(), $columnType);
217+
}
218+
219+
return $columnType;
220+
}
212221
}

tests/rules/DoctrineKeyValueStyleRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ public function testRule(): void
8484
'Query error: Column "ada.not_a_column2" does not exist',
8585
120,
8686
],
87+
[
88+
'Query error: Column "typemix.c_int" expects value type int, got type float|int',
89+
128,
90+
],
91+
[
92+
'Query error: Column "typemix.c_int" expects value type int, got type (int|string)',
93+
136,
94+
],
8795
];
8896

8997
$this->analyse([__DIR__ . '/data/doctrine-key-value-style.php'], $expectedErrors);

0 commit comments

Comments
 (0)