Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 45b6fe9

Browse files
EntityColumnRule, EntityRelationRule - read property type from ClassPropertyNode
1 parent 6f700f8 commit 45b6fe9

File tree

4 files changed

+53
-38
lines changed

4 files changed

+53
-38
lines changed

‎composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
],
88
"require": {
99
"php": "^7.2 || ^8.0",
10-
"phpstan/phpstan": "^1.8.6"
10+
"phpstan/phpstan": "^1.8.11"
1111
},
1212
"conflict": {
1313
"doctrine/collections": "<1.0",

‎phpstan-baseline.neon

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ parameters:
55
count: 1
66
path: src/Doctrine/Mapping/ClassMetadataFactory.php
77

8+
-
9+
message: "#^Calling PHPStan\\\\Type\\\\ParserNodeTypeToPHPStanType\\:\\:resolve\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#"
10+
count: 1
11+
path: src/Rules/Doctrine/ORM/EntityColumnRule.php
12+
13+
-
14+
message: "#^Calling PHPStan\\\\Type\\\\TypehintHelper\\:\\:decideType\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#"
15+
count: 1
16+
path: src/Rules/Doctrine/ORM/EntityColumnRule.php
17+
18+
-
19+
message: "#^Calling PHPStan\\\\Type\\\\ParserNodeTypeToPHPStanType\\:\\:resolve\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#"
20+
count: 1
21+
path: src/Rules/Doctrine/ORM/EntityRelationRule.php
22+
23+
-
24+
message: "#^Calling PHPStan\\\\Type\\\\TypehintHelper\\:\\:decideType\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#"
25+
count: 1
26+
path: src/Rules/Doctrine/ORM/EntityRelationRule.php
27+
828
-
929
message: "#^Call to method getProperty\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#"
1030
count: 1

‎src/Rules/Doctrine/ORM/EntityColumnRule.php

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Node\ClassPropertyNode;
8-
use PHPStan\Reflection\MissingPropertyFromReflectionException;
98
use PHPStan\Reflection\ReflectionProvider;
109
use PHPStan\Rules\Rule;
1110
use PHPStan\Type\ArrayType;
@@ -16,8 +15,10 @@
1615
use PHPStan\Type\MixedType;
1716
use PHPStan\Type\NeverType;
1817
use PHPStan\Type\ObjectType;
18+
use PHPStan\Type\ParserNodeTypeToPHPStanType;
1919
use PHPStan\Type\Type;
2020
use PHPStan\Type\TypeCombinator;
21+
use PHPStan\Type\TypehintHelper;
2122
use PHPStan\Type\TypeTraverser;
2223
use PHPStan\Type\VerbosityLevel;
2324
use Throwable;
@@ -88,12 +89,6 @@ public function processNode(Node $node, Scope $scope): array
8889
}
8990

9091
$propertyName = $node->getName();
91-
try {
92-
$property = $class->getNativeProperty($propertyName);
93-
} catch (MissingPropertyFromReflectionException $e) {
94-
return [];
95-
}
96-
9792
if (!isset($metadata->fieldMappings[$propertyName])) {
9893
return [];
9994
}
@@ -157,8 +152,11 @@ public function processNode(Node $node, Scope $scope): array
157152
$writableToDatabaseType = TypeCombinator::addNull($writableToDatabaseType);
158153
}
159154

160-
$propertyWritableType = $property->getWritableType();
161-
if (get_class($propertyWritableType) === MixedType::class || $propertyWritableType instanceof ErrorType || $propertyWritableType instanceof NeverType) {
155+
$phpDocType = $node->getPhpDocType();
156+
$nativeType = $node->getNativeType() !== null ? ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $scope->getClassReflection()) : new MixedType();
157+
$propertyType = TypehintHelper::decideType($nativeType, $phpDocType);
158+
159+
if (get_class($propertyType) === MixedType::class || $propertyType instanceof ErrorType || $propertyType instanceof NeverType) {
162160
return [];
163161
}
164162

@@ -170,32 +168,31 @@ public function processNode(Node $node, Scope $scope): array
170168
return $traverse($type);
171169
};
172170

173-
$propertyWritableType = TypeTraverser::map($propertyWritableType, $transformArrays);
171+
$propertyTransformedType = TypeTraverser::map($propertyType, $transformArrays);
174172

175-
if (!$propertyWritableType->isSuperTypeOf($writableToPropertyType)->yes()) {
173+
if (!$propertyTransformedType->isSuperTypeOf($writableToPropertyType)->yes()) {
176174
$errors[] = sprintf(
177175
'Property %s::$%s type mapping mismatch: database can contain %s but property expects %s.',
178176
$className,
179177
$propertyName,
180-
$writableToPropertyType->describe(VerbosityLevel::getRecommendedLevelByType($propertyWritableType, $writableToPropertyType)),
181-
$property->getWritableType()->describe(VerbosityLevel::getRecommendedLevelByType($propertyWritableType, $writableToPropertyType))
178+
$writableToPropertyType->describe(VerbosityLevel::getRecommendedLevelByType($propertyTransformedType, $writableToPropertyType)),
179+
$propertyType->describe(VerbosityLevel::getRecommendedLevelByType($propertyTransformedType, $writableToPropertyType))
182180
);
183181
}
184-
$propertyReadableType = TypeTraverser::map($property->getReadableType(), $transformArrays);
185182

186183
if (
187184
!$writableToDatabaseType->isSuperTypeOf(
188185
$this->allowNullablePropertyForRequiredField || (in_array($propertyName, $identifiers, true) && !$nullable)
189-
? TypeCombinator::removeNull($propertyReadableType)
190-
: $propertyReadableType
186+
? TypeCombinator::removeNull($propertyTransformedType)
187+
: $propertyTransformedType
191188
)->yes()
192189
) {
193190
$errors[] = sprintf(
194191
'Property %s::$%s type mapping mismatch: property can contain %s but database expects %s.',
195192
$className,
196193
$propertyName,
197-
$propertyReadableType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyReadableType)),
198-
$writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyReadableType))
194+
$propertyTransformedType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyTransformedType)),
195+
$writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyTransformedType))
199196
);
200197
}
201198
return $errors;

‎src/Rules/Doctrine/ORM/EntityRelationRule.php

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Node\ClassPropertyNode;
8-
use PHPStan\Reflection\MissingPropertyFromReflectionException;
98
use PHPStan\Rules\Rule;
109
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
1110
use PHPStan\Type\ErrorType;
1211
use PHPStan\Type\IterableType;
1312
use PHPStan\Type\MixedType;
1413
use PHPStan\Type\NeverType;
1514
use PHPStan\Type\ObjectType;
15+
use PHPStan\Type\ParserNodeTypeToPHPStanType;
1616
use PHPStan\Type\TypeCombinator;
17+
use PHPStan\Type\TypehintHelper;
1718
use PHPStan\Type\VerbosityLevel;
1819
use Throwable;
1920
use function get_class;
@@ -69,12 +70,6 @@ public function processNode(Node $node, Scope $scope): array
6970
}
7071

7172
$propertyName = $node->getName();
72-
try {
73-
$property = $class->getNativeProperty($propertyName);
74-
} catch (MissingPropertyFromReflectionException $e) {
75-
return [];
76-
}
77-
7873
if (!isset($metadata->associationMappings[$propertyName])) {
7974
return [];
8075
}
@@ -110,46 +105,49 @@ public function processNode(Node $node, Scope $scope): array
110105
);
111106
}
112107

108+
$phpDocType = $node->getPhpDocType();
109+
$nativeType = $node->getNativeType() !== null ? ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $scope->getClassReflection()) : new MixedType();
110+
$propertyType = TypehintHelper::decideType($nativeType, $phpDocType);
111+
113112
$errors = [];
114113
if ($columnType !== null) {
115-
$propertyWritableType = $property->getWritableType();
116-
if (get_class($propertyWritableType) === MixedType::class || $propertyWritableType instanceof ErrorType || $propertyWritableType instanceof NeverType) {
114+
if (get_class($propertyType) === MixedType::class || $propertyType instanceof ErrorType || $propertyType instanceof NeverType) {
117115
return [];
118116
}
119117

120118
$collectionObjectType = new ObjectType('Doctrine\Common\Collections\Collection');
121-
$propertyWritableTypeToCheckAgainst = $propertyWritableType;
119+
$propertyTypeToCheckAgainst = $propertyType;
122120
if (
123121
$toMany
124-
&& $collectionObjectType->isSuperTypeOf($propertyWritableType)->yes()
125-
&& $propertyWritableType->isIterable()->yes()
122+
&& $collectionObjectType->isSuperTypeOf($propertyType)->yes()
123+
&& $propertyType->isIterable()->yes()
126124
) {
127-
$propertyWritableTypeToCheckAgainst = TypeCombinator::intersect(
125+
$propertyTypeToCheckAgainst = TypeCombinator::intersect(
128126
$collectionObjectType,
129-
new IterableType(new MixedType(true), $propertyWritableType->getIterableValueType())
127+
new IterableType(new MixedType(true), $propertyType->getIterableValueType())
130128
);
131129
}
132-
if (!$propertyWritableTypeToCheckAgainst->isSuperTypeOf($columnType)->yes()) {
130+
if (!$propertyTypeToCheckAgainst->isSuperTypeOf($columnType)->yes()) {
133131
$errors[] = sprintf(
134132
'Property %s::$%s type mapping mismatch: database can contain %s but property expects %s.',
135133
$className,
136134
$propertyName,
137135
$columnType->describe(VerbosityLevel::typeOnly()),
138-
$propertyWritableType->describe(VerbosityLevel::typeOnly())
136+
$propertyType->describe(VerbosityLevel::typeOnly())
139137
);
140138
}
141139
if (
142140
!$columnType->isSuperTypeOf(
143141
$this->allowNullablePropertyForRequiredField
144-
? TypeCombinator::removeNull($property->getReadableType())
145-
: $property->getReadableType()
142+
? TypeCombinator::removeNull($propertyType)
143+
: $propertyType
146144
)->yes()
147145
) {
148146
$errors[] = sprintf(
149147
'Property %s::$%s type mapping mismatch: property can contain %s but database expects %s.',
150148
$className,
151149
$propertyName,
152-
$property->getReadableType()->describe(VerbosityLevel::typeOnly()),
150+
$propertyType->describe(VerbosityLevel::typeOnly()),
153151
$columnType->describe(VerbosityLevel::typeOnly())
154152
);
155153
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /