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 7480e9d

Browse files
committed
Create ServiceMap from AutowireLoader property
This allows us to share the logic for other rules
1 parent 534b45d commit 7480e9d

File tree

2 files changed

+113
-56
lines changed

2 files changed

+113
-56
lines changed

‎src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php‎

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,15 @@
55
use PhpParser\Node;
66
use PhpParser\Node\Expr\MethodCall;
77
use PHPStan\Analyser\Scope;
8-
use PHPStan\BetterReflection\Reflection\Adapter\FakeReflectionAttribute;
9-
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionAttribute;
10-
use PHPStan\Reflection\ClassReflection;
118
use PHPStan\Rules\Rule;
129
use PHPStan\Rules\RuleErrorBuilder;
10+
use PHPStan\Symfony\AutowireLoaderServiceMapFactory;
11+
use PHPStan\Symfony\DefaultServiceMap;
1312
use PHPStan\Symfony\ServiceMap;
1413
use PHPStan\TrinaryLogic;
1514
use PHPStan\Type\ObjectType;
1615
use PHPStan\Type\Type;
17-
use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
18-
use function class_exists;
16+
use function is_null;
1917
use function sprintf;
2018

2119
/**
@@ -78,7 +76,7 @@ public function processNode(Node $node, Scope $scope): array
7876
$isContainerInterfaceType = $isContainerType->yes() || $isPsrContainerType->yes();
7977
if (
8078
$isContainerInterfaceType &&
81-
$this->isAutowireLocator($node, $scope, $serviceId)
79+
$this->isAutowireLocatorService($node, $scope, $serviceId)
8280
) {
8381
return [];
8482
}
@@ -107,61 +105,16 @@ private function isServiceSubscriber(Type $containerType, Scope $scope): Trinary
107105
return $isContainerServiceSubscriber->or($serviceSubscriberInterfaceType->isSuperTypeOf($containedClassType));
108106
}
109107

110-
private function isAutowireLocator(Node $node, Scope $scope, string $serviceId): bool
108+
private function isAutowireLocatorService(Node $node, Scope $scope, string $serviceId): bool
111109
{
112-
if (!class_exists('Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator')) {
113-
return false;
114-
}
115-
116-
if (
117-
!$node instanceof MethodCall
118-
) {
119-
return false;
120-
}
121-
122-
$nodeParentProperty = $node->var;
123-
124-
if (!$nodeParentProperty instanceof Node\Expr\PropertyFetch) {
125-
return false;
126-
}
110+
$autowireLocatorServiceMapFactory = new AutowireLoaderServiceMapFactory($node, $scope);
111+
$autowireLocatorServiceMap = $autowireLocatorServiceMapFactory->create();
127112

128-
$nodeParentPropertyName = $nodeParentProperty->name;
129-
130-
if (!$nodeParentPropertyName instanceof Node\Identifier) {
131-
return false;
132-
}
133-
134-
$containerInterfacePropertyName = $nodeParentPropertyName->name;
135-
$scopeClassReflection = $scope->getClassReflection();
136-
137-
if (!$scopeClassReflection instanceof ClassReflection) {
113+
if (!$autowireLocatorServiceMap instanceof DefaultServiceMap) {
138114
return false;
139115
}
140116

141-
$containerInterfacePropertyReflection = $scopeClassReflection
142-
->getNativeProperty($containerInterfacePropertyName);
143-
$classPropertyReflection = $containerInterfacePropertyReflection->getNativeReflection();
144-
$autowireLocatorAttributes = $classPropertyReflection->getAttributes(AutowireLocator::class);
145-
146-
return $this->isAutowireLocatorService($autowireLocatorAttributes, $serviceId);
147-
}
148-
149-
/**
150-
* @param array<int, FakeReflectionAttribute|ReflectionAttribute> $autowireLocatorAttributes
151-
*/
152-
private function isAutowireLocatorService(array $autowireLocatorAttributes, string $serviceId): bool
153-
{
154-
foreach ($autowireLocatorAttributes as $autowireLocatorAttribute) {
155-
/** @var AutowireLocator $autowireLocatorInstance */
156-
$autowireLocator = $autowireLocatorAttribute->newInstance();
157-
$autowireLocatorServices = $autowireLocator->value->getValues();
158-
159-
if (array_key_exists($serviceId, $autowireLocatorServices)) {
160-
return true;
161-
}
162-
}
163-
164-
return false;
117+
return !is_null($autowireLocatorServiceMap->getService($serviceId));
165118
}
166119

167120
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Symfony;
4+
5+
use InvalidArgumentException;
6+
use PhpParser\Node;
7+
use PhpParser\Node\Expr\MethodCall;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Reflection\ClassReflection;
10+
use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
11+
use Symfony\Component\DependencyInjection\TypedReference;
12+
use function class_exists;
13+
use function count;
14+
use function sprintf;
15+
16+
final class AutowireLoaderServiceMapFactory implements ServiceMapFactory
17+
{
18+
19+
/** @var Node */
20+
private $node;
21+
22+
/** @var Scope */
23+
private $scope;
24+
25+
public function __construct(
26+
Node $node,
27+
Scope $scope
28+
)
29+
{
30+
$this->node = $node;
31+
$this->scope = $scope;
32+
}
33+
34+
public function create(): ServiceMap
35+
{
36+
if (!class_exists('Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator')) {
37+
return new FakeServiceMap();
38+
}
39+
40+
if (!$this->node instanceof MethodCall) {
41+
return new FakeServiceMap();
42+
}
43+
44+
$nodeParentProperty = $this->node->var;
45+
46+
if (!$nodeParentProperty instanceof Node\Expr\PropertyFetch) {
47+
return new FakeServiceMap();
48+
}
49+
50+
$nodeParentPropertyName = $nodeParentProperty->name;
51+
52+
if (!$nodeParentPropertyName instanceof Node\Identifier) {
53+
return new FakeServiceMap();
54+
}
55+
56+
$containerInterfacePropertyName = $nodeParentPropertyName->name;
57+
$scopeClassReflection = $this->scope->getClassReflection();
58+
59+
if (!$scopeClassReflection instanceof ClassReflection) {
60+
return new FakeServiceMap();
61+
}
62+
63+
$containerInterfacePropertyReflection = $scopeClassReflection
64+
->getNativeProperty($containerInterfacePropertyName);
65+
$classPropertyReflection = $containerInterfacePropertyReflection->getNativeReflection();
66+
$autowireLocatorAttributesReflection = $classPropertyReflection->getAttributes(AutowireLocator::class);
67+
68+
if (count($autowireLocatorAttributesReflection) === 0) {
69+
return new FakeServiceMap();
70+
}
71+
72+
if (count($autowireLocatorAttributesReflection) > 1) {
73+
throw new InvalidArgumentException(sprintf(
74+
'Only one AutowireLocator attribute is allowed on "%s::%s".',
75+
$scopeClassReflection->getName(),
76+
$containerInterfacePropertyName
77+
));
78+
}
79+
80+
$autowireLocatorAttributeReflection = $autowireLocatorAttributesReflection[0];
81+
/** @var AutowireLocator $autowireLocator */
82+
$autowireLocator = $autowireLocatorAttributeReflection->newInstance();
83+
84+
/** @var Service[] $services */
85+
$services = [];
86+
87+
/** @var TypedReference $service */
88+
foreach ($autowireLocator->value->getValues() as $id => $service) {
89+
$class = $service->getType();
90+
$alias = $service->getName();
91+
92+
$services[$id] = new Service(
93+
$id,
94+
$class,
95+
true,
96+
false,
97+
$alias
98+
);
99+
}
100+
101+
return new DefaultServiceMap($services);
102+
}
103+
104+
}

0 commit comments

Comments
(0)

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