forked from phpstan/phpstan-doctrine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEntityRepositoryClassReflectionExtension.php
More file actions
118 lines (100 loc) · 3.35 KB
/
EntityRepositoryClassReflectionExtension.php
File metadata and controls
118 lines (100 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?php declare(strict_types = 1);
namespace PHPStan\Reflection\Doctrine;
use Doctrine\Persistence\ObjectRepository;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\MethodsClassReflectionExtension;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
use PHPStan\Type\IntegerType;
use PHPStan\Type\TypeCombinator;
use function lcfirst;
use function str_replace;
use function strlen;
use function strpos;
use function substr;
use function ucwords;
class EntityRepositoryClassReflectionExtension implements MethodsClassReflectionExtension
{
private ObjectMetadataResolver $objectMetadataResolver;
public function __construct(ObjectMetadataResolver $objectMetadataResolver)
{
$this->objectMetadataResolver = $objectMetadataResolver;
}
public function hasMethod(ClassReflection $classReflection, string $methodName): bool
{
if (
strpos($methodName, 'findBy') === 0
&& strlen($methodName) > strlen('findBy')
) {
$methodFieldName = substr($methodName, strlen('findBy'));
} elseif (
strpos($methodName, 'findOneBy') === 0
&& strlen($methodName) > strlen('findOneBy')
) {
$methodFieldName = substr($methodName, strlen('findOneBy'));
} elseif (
strpos($methodName, 'countBy') === 0
&& strlen($methodName) > strlen('countBy')
) {
$methodFieldName = substr($methodName, strlen('countBy'));
} else {
return false;
}
$repositoryAncesor = $classReflection->getAncestorWithClassName(ObjectRepository::class);
if ($repositoryAncesor === null) {
return false;
}
$templateTypeMap = $repositoryAncesor->getActiveTemplateTypeMap();
$entityClassType = $templateTypeMap->getType('TEntityClass');
if ($entityClassType === null) {
return false;
}
$entityClassNames = $entityClassType->getObjectClassNames();
$fieldName = $this->classify($methodFieldName);
/** @var class-string $entityClassName */
foreach ($entityClassNames as $entityClassName) {
$classMetadata = $this->objectMetadataResolver->getClassMetadata($entityClassName);
if ($classMetadata === null) {
continue;
}
if ($classMetadata->hasField($fieldName) || $classMetadata->hasAssociation($fieldName)) {
return true;
}
}
return false;
}
private function classify(string $word): string
{
return lcfirst(str_replace([' ', '_', '-'], '', ucwords($word, ' _-')));
}
public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection
{
$repositoryAncesor = $classReflection->getAncestorWithClassName(ObjectRepository::class);
if ($repositoryAncesor === null) {
throw new ShouldNotHappenException();
}
$templateTypeMap = $repositoryAncesor->getActiveTemplateTypeMap();
$entityClassType = $templateTypeMap->getType('TEntityClass');
if ($entityClassType === null) {
throw new ShouldNotHappenException();
}
if (
strpos($methodName, 'findBy') === 0
) {
$returnType = new ArrayType(new IntegerType(), $entityClassType);
} elseif (
strpos($methodName, 'findOneBy') === 0
) {
$returnType = TypeCombinator::addNull($entityClassType);
} elseif (
strpos($methodName, 'countBy') === 0
) {
$returnType = new IntegerType();
} else {
throw new ShouldNotHappenException();
}
return new MagicRepositoryMethodReflection($repositoryAncesor, $methodName, $returnType);
}
}