Skip to content

Commit eeff198

Browse files
VincentLangletondrejmirtes
authored andcommitted
Improve EntityColumnRule for enums
1 parent cb37e28 commit eeff198

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

src/Rules/Doctrine/ORM/EntityColumnRule.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PHPStan\Rules\Rule;
1010
use PHPStan\Rules\RuleErrorBuilder;
1111
use PHPStan\Type\ArrayType;
12+
use PHPStan\Type\Constant\ConstantStringType;
1213
use PHPStan\Type\Doctrine\DescriptorNotRegisteredException;
1314
use PHPStan\Type\Doctrine\DescriptorRegistry;
1415
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
@@ -21,10 +22,14 @@
2122
use PHPStan\Type\TypehintHelper;
2223
use PHPStan\Type\TypeTraverser;
2324
use PHPStan\Type\TypeUtils;
25+
use PHPStan\Type\UnionType;
2426
use PHPStan\Type\VerbosityLevel;
2527
use Throwable;
28+
use function count;
2629
use function get_class;
2730
use function in_array;
31+
use function is_array;
32+
use function is_string;
2833
use function sprintf;
2934

3035
/**
@@ -100,6 +105,26 @@ public function processNode(Node $node, Scope $scope): array
100105
$writableToPropertyType = $descriptor->getWritableToPropertyType();
101106
$writableToDatabaseType = $descriptor->getWritableToDatabaseType();
102107

108+
if ($fieldMapping['type'] === 'enum') {
109+
$values = $fieldMapping['options']['values'] ?? null;
110+
if (is_array($values)) {
111+
$enumTypes = [];
112+
foreach ($values as $value) {
113+
if (!is_string($value)) {
114+
$enumTypes = [];
115+
break;
116+
}
117+
118+
$enumTypes[] = new ConstantStringType($value);
119+
}
120+
121+
if (count($enumTypes) > 0) {
122+
$writableToPropertyType = new UnionType($enumTypes);
123+
$writableToDatabaseType = new UnionType($enumTypes);
124+
}
125+
}
126+
}
127+
103128
$enumTypeString = $fieldMapping['enumType'] ?? null;
104129
if ($enumTypeString !== null) {
105130
if ($writableToDatabaseType->isArray()->no() && $writableToPropertyType->isArray()->no()) {

tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPStan\Type\Doctrine\Descriptors\DateTimeType;
1919
use PHPStan\Type\Doctrine\Descriptors\DateType;
2020
use PHPStan\Type\Doctrine\Descriptors\DecimalType;
21+
use PHPStan\Type\Doctrine\Descriptors\EnumType;
2122
use PHPStan\Type\Doctrine\Descriptors\IntegerType;
2223
use PHPStan\Type\Doctrine\Descriptors\JsonType;
2324
use PHPStan\Type\Doctrine\Descriptors\Ramsey\UuidTypeDescriptor;
@@ -26,6 +27,7 @@
2627
use PHPStan\Type\Doctrine\Descriptors\StringType;
2728
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
2829
use function array_unshift;
30+
use function class_exists;
2931
use function strpos;
3032
use const PHP_VERSION_ID;
3133

@@ -75,6 +77,7 @@ protected function getRule(): Rule
7577
new StringType(),
7678
new SimpleArrayType(),
7779
new UuidTypeDescriptor(FakeTestingUuidType::class),
80+
new EnumType(),
7881
new ReflectionDescriptor(CarbonImmutableType::class, $this->createReflectionProvider(), self::getContainer()),
7982
new ReflectionDescriptor(CarbonType::class, $this->createReflectionProvider(), self::getContainer()),
8083
new ReflectionDescriptor(CustomType::class, $this->createReflectionProvider(), self::getContainer()),
@@ -441,4 +444,21 @@ public function testBug306(?string $objectManagerLoader): void
441444
]);
442445
}
443446

447+
/**
448+
* @dataProvider dataObjectManagerLoader
449+
*/
450+
public function testBug677(?string $objectManagerLoader): void
451+
{
452+
if (PHP_VERSION_ID < 80100) {
453+
self::markTestSkipped('Test requires PHP 8.1');
454+
}
455+
if (!class_exists(\Doctrine\DBAL\Types\EnumType::class)) {
456+
self::markTestSkipped('Test requires EnumType.');
457+
}
458+
459+
$this->allowNullablePropertyForRequiredField = false;
460+
$this->objectManagerLoader = $objectManagerLoader;
461+
$this->analyse([__DIR__ . '/data/bug-677.php'], []);
462+
}
463+
444464
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php // lint >= 8.1
2+
3+
namespace PHPStan\Rules\Doctrine\ORM\Bug677;
4+
5+
use Doctrine\ORM\Mapping as ORM;
6+
7+
#[ORM\Entity]
8+
class MyBrokenEntity
9+
{
10+
public const LOGIN_METHOD_BASIC_AUTH = 'BasicAuth';
11+
public const LOGIN_METHOD_SSO = 'SSO';
12+
public const LOGIN_METHOD_SAML = 'SAML';
13+
14+
public const LOGIN_METHODS = [
15+
self::LOGIN_METHOD_BASIC_AUTH,
16+
self::LOGIN_METHOD_SSO,
17+
self::LOGIN_METHOD_SAML,
18+
];
19+
20+
/**
21+
* @var int|null
22+
*/
23+
#[ORM\Id]
24+
#[ORM\GeneratedValue]
25+
#[ORM\Column(type: 'integer')]
26+
private $id;
27+
28+
/**
29+
* @var self::LOGIN_METHOD_*
30+
*/
31+
#[ORM\Column(name: 'login_method', type: 'enum', options: ['default' => self::LOGIN_METHOD_BASIC_AUTH, 'values' => self::LOGIN_METHODS])]
32+
private string $loginMethod = self::LOGIN_METHOD_BASIC_AUTH;
33+
}

0 commit comments

Comments
 (0)