Skip to content

Commit 2c339ca

Browse files
authored
Improve the type descriptor for SimpleArrayType
1 parent 6d65f89 commit 2c339ca

File tree

7 files changed

+55
-8
lines changed

7 files changed

+55
-8
lines changed

src/Rules/Doctrine/ORM/EntityColumnRule.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,14 @@ public function processNode(Node $node, Scope $scope): array
160160
return [];
161161
}
162162

163-
$propertyTransformedType = TypeTraverser::map($propertyType, static function (Type $type, callable $traverse): Type {
163+
// If the type descriptor does not precise the types inside the array, don't report errors if the field has a more precise type
164+
$propertyTransformedType = $writableToPropertyType->equals(new ArrayType(new MixedType(), new MixedType())) ? TypeTraverser::map($propertyType, static function (Type $type, callable $traverse): Type {
164165
if ($type instanceof ArrayType) {
165166
return new ArrayType(new MixedType(), new MixedType());
166167
}
167168

168169
return $traverse($type);
169-
});
170+
}) : $propertyType;
170171

171172
if (!$propertyTransformedType->isSuperTypeOf($writableToPropertyType)->yes()) {
172173
$errors[] = sprintf(
@@ -181,16 +182,16 @@ public function processNode(Node $node, Scope $scope): array
181182
if (
182183
!$writableToDatabaseType->isSuperTypeOf(
183184
$this->allowNullablePropertyForRequiredField || (in_array($propertyName, $identifiers, true) && !$nullable)
184-
? TypeCombinator::removeNull($propertyTransformedType)
185-
: $propertyTransformedType
185+
? TypeCombinator::removeNull($propertyType)
186+
: $propertyType
186187
)->yes()
187188
) {
188189
$errors[] = sprintf(
189190
'Property %s::$%s type mapping mismatch: property can contain %s but database expects %s.',
190191
$className,
191192
$propertyName,
192-
$propertyTransformedType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyTransformedType)),
193-
$writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyTransformedType))
193+
$propertyTransformedType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyType)),
194+
$writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyType))
194195
);
195196
}
196197
return $errors;

src/Type/Doctrine/Descriptors/SimpleArrayType.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace PHPStan\Type\Doctrine\Descriptors;
44

5+
use PHPStan\Type\Accessory\AccessoryArrayListType;
56
use PHPStan\Type\ArrayType;
7+
use PHPStan\Type\IntegerType;
68
use PHPStan\Type\MixedType;
79
use PHPStan\Type\StringType;
810
use PHPStan\Type\Type;
@@ -17,12 +19,12 @@ public function getType(): string
1719

1820
public function getWritableToPropertyType(): Type
1921
{
20-
return new ArrayType(new MixedType(), new MixedType());
22+
return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType()));
2123
}
2224

2325
public function getWritableToDatabaseType(): Type
2426
{
25-
return new ArrayType(new MixedType(), new MixedType());
27+
return new ArrayType(new MixedType(), new StringType());
2628
}
2729

2830
public function getDatabaseInternalType(): Type

tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PHPStan\Type\Doctrine\Descriptors\JsonType;
2121
use PHPStan\Type\Doctrine\Descriptors\Ramsey\UuidTypeDescriptor;
2222
use PHPStan\Type\Doctrine\Descriptors\ReflectionDescriptor;
23+
use PHPStan\Type\Doctrine\Descriptors\SimpleArrayType;
2324
use PHPStan\Type\Doctrine\Descriptors\StringType;
2425
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
2526
use Ramsey\Uuid\Doctrine\UuidType;
@@ -68,6 +69,7 @@ protected function getRule(): Rule
6869
new JsonType(),
6970
new IntegerType(),
7071
new StringType(),
72+
new SimpleArrayType(),
7173
new UuidTypeDescriptor(UuidType::class),
7274
new ReflectionDescriptor(CarbonImmutableType::class, $this->createBroker()),
7375
new ReflectionDescriptor(CarbonType::class, $this->createBroker()),
@@ -156,6 +158,14 @@ public function testRule(?string $objectManagerLoader): void
156158
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$incompatibleJsonValueObject type mapping mismatch: property can contain PHPStan\Rules\Doctrine\ORM\EmptyObject but database expects array|bool|float|int|JsonSerializable|stdClass|string|null.',
157159
156,
158160
],
161+
[
162+
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain array<int, string> but property expects array<int>.',
163+
162,
164+
],
165+
[
166+
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array<int> but database expects array<string>.',
167+
162,
168+
],
159169
]);
160170
}
161171

@@ -211,6 +221,14 @@ public function testRuleWithAllowedNullableProperty(?string $objectManagerLoader
211221
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$incompatibleJsonValueObject type mapping mismatch: property can contain PHPStan\Rules\Doctrine\ORM\EmptyObject but database expects array|bool|float|int|JsonSerializable|stdClass|string|null.',
212222
156,
213223
],
224+
[
225+
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain array<int, string> but property expects array<int>.',
226+
162,
227+
],
228+
[
229+
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array<int> but database expects array<string>.',
230+
162,
231+
],
214232
]);
215233
}
216234

tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,16 @@ class MyBrokenEntity extends MyBrokenSuperclass
154154
* @var EmptyObject
155155
*/
156156
private $incompatibleJsonValueObject;
157+
158+
/**
159+
* @ORM\Column(type="simple_array")
160+
* @var int[]
161+
*/
162+
private $invalidSimpleArray;
163+
164+
/**
165+
* @ORM\Column(type="simple_array")
166+
* @var list<string>
167+
*/
168+
private $validSimpleArray;
157169
}

tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ public static function setUpBeforeClass(): void
132132
$many->stringNullColumn = $stringNullColumnMany;
133133
$many->datetimeColumn = new DateTime('2001-01-01 00:00:00');
134134
$many->datetimeImmutableColumn = new DateTimeImmutable('2001-01-01 00:00:00');
135+
$many->simpleArrayColumn = ['foo'];
135136
$many->one = $one;
136137
$one->manies->add($many);
137138
$em->persist($many);

tests/Type/Doctrine/data/QueryResult/Entities/Many.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ class Many
102102
* @var CompoundPkAssoc|null
103103
*/
104104
public $compoundPkAssoc;
105+
106+
/**
107+
* @ORM\Column(type="simple_array")
108+
* @var list<string>
109+
*/
110+
public $simpleArrayColumn;
105111
}
106112

107113
/**

tests/Type/Doctrine/data/QueryResult/createQuery.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ public function testQueryTypeParametersAreInfered(EntityManagerInterface $em): v
2525
assertType('Doctrine\ORM\Query<null, array{intColumn: int, stringNullColumn: string|null}>', $query);
2626
}
2727

28+
public function testQueryTypeSimpleArray(EntityManagerInterface $em): void
29+
{
30+
$query = $em->createQuery('SELECT m.simpleArrayColumn FROM QueryResult\Entities\Many m');
31+
32+
assertType('Doctrine\ORM\Query<null, array{simpleArrayColumn: list<string>}>', $query);
33+
}
34+
2835
public function testQueryResultTypeIsMixedWhenDQLIsNotKnown(EntityManagerInterface $em, string $dql): void
2936
{
3037
$query = $em->createQuery($dql);

0 commit comments

Comments
 (0)