Skip to content

Commit ec67d0c

Browse files
Improve EntityColumnRule for enums
1 parent 6fe9e9d commit ec67d0c

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-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: 18 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;
@@ -59,6 +60,9 @@ protected function getRule(): Rule
5960
if (!Type::hasType('array')) {
6061
Type::addType('array', \Doctrine\DBAL\Types\ArrayType::class);
6162
}
63+
if (!Type::hasType('enum')) {
64+
Type::addType('enum', \Doctrine\DBAL\Types\EnumType::class);
65+
}
6266

6367
return new EntityColumnRule(
6468
new ObjectMetadataResolver($this->objectManagerLoader, __DIR__ . '/../../../../tmp'),
@@ -75,6 +79,7 @@ protected function getRule(): Rule
7579
new StringType(),
7680
new SimpleArrayType(),
7781
new UuidTypeDescriptor(FakeTestingUuidType::class),
82+
new EnumType(),
7883
new ReflectionDescriptor(CarbonImmutableType::class, $this->createReflectionProvider(), self::getContainer()),
7984
new ReflectionDescriptor(CarbonType::class, $this->createReflectionProvider(), self::getContainer()),
8085
new ReflectionDescriptor(CustomType::class, $this->createReflectionProvider(), self::getContainer()),
@@ -441,4 +446,17 @@ public function testBug306(?string $objectManagerLoader): void
441446
]);
442447
}
443448

449+
/**
450+
* @dataProvider dataObjectManagerLoader
451+
*/
452+
public function testBug677(?string $objectManagerLoader): void
453+
{
454+
if (PHP_VERSION_ID < 80100) {
455+
self::markTestSkipped('Test requires PHP 8.1');
456+
}
457+
$this->allowNullablePropertyForRequiredField = false;
458+
$this->objectManagerLoader = $objectManagerLoader;
459+
$this->analyse([__DIR__ . '/data/bug-677.php'], []);
460+
}
461+
444462
}
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)