Skip to content

Commit

Permalink
Improve the type descriptor for SimpleArrayType
Browse files Browse the repository at this point in the history
  • Loading branch information
stof committed Apr 6, 2023
1 parent 6d65f89 commit 2c339ca
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 8 deletions.
13 changes: 7 additions & 6 deletions src/Rules/Doctrine/ORM/EntityColumnRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,14 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

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

return $traverse($type);
});
}) : $propertyType;

if (!$propertyTransformedType->isSuperTypeOf($writableToPropertyType)->yes()) {
$errors[] = sprintf(
Expand All @@ -181,16 +182,16 @@ public function processNode(Node $node, Scope $scope): array
if (
!$writableToDatabaseType->isSuperTypeOf(
$this->allowNullablePropertyForRequiredField || (in_array($propertyName, $identifiers, true) && !$nullable)
? TypeCombinator::removeNull($propertyTransformedType)
: $propertyTransformedType
? TypeCombinator::removeNull($propertyType)
: $propertyType
)->yes()
) {
$errors[] = sprintf(
'Property %s::$%s type mapping mismatch: property can contain %s but database expects %s.',
$className,
$propertyName,
$propertyTransformedType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyTransformedType)),
$writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyTransformedType))
$propertyTransformedType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyType)),
$writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyType))
);
}
return $errors;
Expand Down
6 changes: 4 additions & 2 deletions src/Type/Doctrine/Descriptors/SimpleArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace PHPStan\Type\Doctrine\Descriptors;

use PHPStan\Type\Accessory\AccessoryArrayListType;
use PHPStan\Type\ArrayType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
Expand All @@ -17,12 +19,12 @@ public function getType(): string

public function getWritableToPropertyType(): Type
{
return new ArrayType(new MixedType(), new MixedType());
return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType()));
}

public function getWritableToDatabaseType(): Type
{
return new ArrayType(new MixedType(), new MixedType());
return new ArrayType(new MixedType(), new StringType());
}

public function getDatabaseInternalType(): Type
Expand Down
18 changes: 18 additions & 0 deletions tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use PHPStan\Type\Doctrine\Descriptors\JsonType;
use PHPStan\Type\Doctrine\Descriptors\Ramsey\UuidTypeDescriptor;
use PHPStan\Type\Doctrine\Descriptors\ReflectionDescriptor;
use PHPStan\Type\Doctrine\Descriptors\SimpleArrayType;
use PHPStan\Type\Doctrine\Descriptors\StringType;
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
use Ramsey\Uuid\Doctrine\UuidType;
Expand Down Expand Up @@ -68,6 +69,7 @@ protected function getRule(): Rule
new JsonType(),
new IntegerType(),
new StringType(),
new SimpleArrayType(),
new UuidTypeDescriptor(UuidType::class),
new ReflectionDescriptor(CarbonImmutableType::class, $this->createBroker()),
new ReflectionDescriptor(CarbonType::class, $this->createBroker()),
Expand Down Expand Up @@ -156,6 +158,14 @@ public function testRule(?string $objectManagerLoader): void
'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.',
156,
],
[
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain array<int, string> but property expects array<int>.',
162,
],
[
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array<int> but database expects array<string>.',
162,
],
]);
}

Expand Down Expand Up @@ -211,6 +221,14 @@ public function testRuleWithAllowedNullableProperty(?string $objectManagerLoader
'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.',
156,
],
[
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain array<int, string> but property expects array<int>.',
162,
],
[
'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array<int> but database expects array<string>.',
162,
],
]);
}

Expand Down
12 changes: 12 additions & 0 deletions tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,16 @@ class MyBrokenEntity extends MyBrokenSuperclass
* @var EmptyObject
*/
private $incompatibleJsonValueObject;

/**
* @ORM\Column(type="simple_array")
* @var int[]
*/
private $invalidSimpleArray;

/**
* @ORM\Column(type="simple_array")
* @var list<string>
*/
private $validSimpleArray;
}
1 change: 1 addition & 0 deletions tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public static function setUpBeforeClass(): void
$many->stringNullColumn = $stringNullColumnMany;
$many->datetimeColumn = new DateTime('2001-01-01 00:00:00');
$many->datetimeImmutableColumn = new DateTimeImmutable('2001-01-01 00:00:00');
$many->simpleArrayColumn = ['foo'];
$many->one = $one;
$one->manies->add($many);
$em->persist($many);
Expand Down
6 changes: 6 additions & 0 deletions tests/Type/Doctrine/data/QueryResult/Entities/Many.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ class Many
* @var CompoundPkAssoc|null
*/
public $compoundPkAssoc;

/**
* @ORM\Column(type="simple_array")
* @var list<string>
*/
public $simpleArrayColumn;
}

/**
Expand Down
7 changes: 7 additions & 0 deletions tests/Type/Doctrine/data/QueryResult/createQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ public function testQueryTypeParametersAreInfered(EntityManagerInterface $em): v
assertType('Doctrine\ORM\Query<null, array{intColumn: int, stringNullColumn: string|null}>', $query);
}

public function testQueryTypeSimpleArray(EntityManagerInterface $em): void
{
$query = $em->createQuery('SELECT m.simpleArrayColumn FROM QueryResult\Entities\Many m');

assertType('Doctrine\ORM\Query<null, array{simpleArrayColumn: list<string>}>', $query);
}

public function testQueryResultTypeIsMixedWhenDQLIsNotKnown(EntityManagerInterface $em, string $dql): void
{
$query = $em->createQuery($dql);
Expand Down

0 comments on commit 2c339ca

Please sign in to comment.