forked from ariddlestone/phpstan-cakephp2
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathClassComponentsExtension.php
More file actions
106 lines (85 loc) · 3.17 KB
/
Copy pathClassComponentsExtension.php
File metadata and controls
106 lines (85 loc) · 3.17 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
<?php
declare(strict_types=1);
namespace PHPStanCakePHP2;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\PropertiesClassReflectionExtension;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Reflection\ReflectionProvider;
final class ClassComponentsExtension implements PropertiesClassReflectionExtension
{
private ReflectionProvider $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
}
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool
{
if (!array_filter($this->getContainingClassNames(), [$classReflection, 'is'])) {
return false;
}
$isDefinedInComponentsProperty = (bool) array_filter(
$this->getDefinedComponentsAsList($classReflection),
static fn (string $componentName): bool => $componentName === $propertyName
);
if (!$isDefinedInComponentsProperty) {
return false;
}
$propertyClassName = $this->getClassNameFromPropertyName($propertyName);
return $this->reflectionProvider->hasClass($propertyClassName)
&& $this->reflectionProvider->getClass($propertyClassName)
->is('Component');
}
public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection
{
return new PublicReadOnlyPropertyReflection(
$this->getClassNameFromPropertyName($propertyName),
$classReflection
);
}
/**
* @return array<string>
*/
private function getContainingClassNames(): array
{
return [
'Controller',
'Component',
];
}
private function getClassNameFromPropertyName(string $propertyName): string
{
return str_contains($propertyName, 'Component') ? $propertyName : $propertyName . 'Component';
}
/**
* @return list<string>
*/
private function getDefinedComponentsAsList(ClassReflection $classReflection): array
{
$definedComponents = [];
foreach (array_merge([$classReflection], $classReflection->getParents()) as $class) {
if (!$class->hasProperty('components')) {
continue;
}
$defaultValue = $class->getNativeProperty('components')
->getNativeReflection()
->getDefaultValueExpression();
if (!$defaultValue instanceof Array_) {
continue;
}
foreach ($defaultValue->items as $item) {
if ($item->value instanceof String_) {
$definedComponents[] = $item->value->value;
continue;
}
if ($item->value instanceof ClassConstFetch && $item->value->class instanceof FullyQualified) {
$definedComponents[] = $item->value->class->toString();
}
}
}
return $definedComponents;
}
}