Skip to content

Commit 9932dc0

Browse files
Improve EntityColumnRule for enums
1 parent 6fe9e9d commit 9932dc0

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

src/Rules/Doctrine/ORM/EntityColumnRule.php

Lines changed: 22 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,6 +22,7 @@
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;
2628
use function get_class;
@@ -100,6 +102,26 @@ public function processNode(Node $node, Scope $scope): array
100102
$writableToPropertyType = $descriptor->getWritableToPropertyType();
101103
$writableToDatabaseType = $descriptor->getWritableToDatabaseType();
102104

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

tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,4 +441,17 @@ public function testBug306(?string $objectManagerLoader): void
441441
]);
442442
}
443443

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