1 | <?php |
||||
2 | declare(strict_types=1); |
||||
3 | |||||
4 | namespace DependencyAnalyzer; |
||||
5 | |||||
6 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\Base as DependencyType; |
||||
7 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\ConstantFetch; |
||||
8 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\ExtendsClass; |
||||
9 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\ImplementsClass; |
||||
10 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\MethodCall; |
||||
11 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\NewObject; |
||||
12 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\PropertyFetch; |
||||
13 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\SomeDependency; |
||||
14 | use DependencyAnalyzer\DependencyGraph\DependencyTypes\UseTrait; |
||||
15 | use DependencyAnalyzer\DependencyGraph\ExtraPhpDocTags\DepsInternal; |
||||
16 | use DependencyAnalyzer\DependencyGraph\ExtraPhpDocTags\Internal; |
||||
17 | use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName; |
||||
18 | use DependencyAnalyzer\DependencyGraphBuilder\ExtraPhpDocTagResolver; |
||||
19 | use DependencyAnalyzer\DependencyGraphBuilder\ObserverInterface; |
||||
20 | use DependencyAnalyzer\DependencyGraphBuilder\UnknownReflectionClass; |
||||
21 | use DependencyAnalyzer\Exceptions\LogicException; |
||||
22 | use Fhaculty\Graph\Graph; |
||||
23 | use Fhaculty\Graph\Vertex; |
||||
24 | use ReflectionClass; |
||||
25 | |||||
26 | class DependencyGraphBuilder |
||||
27 | { |
||||
28 | /** |
||||
29 | * @var Graph |
||||
30 | */ |
||||
31 | protected $graph; |
||||
32 | |||||
33 | /** |
||||
34 | * @var ExtraPhpDocTagResolver |
||||
35 | */ |
||||
36 | protected $extraPhpDocTagResolver; |
||||
37 | |||||
38 | public function __construct(ExtraPhpDocTagResolver $extraPhpDocTagResolver) |
||||
39 | { |
||||
40 | $this->graph = new Graph; |
||||
41 | $this->extraPhpDocTagResolver = $extraPhpDocTagResolver; |
||||
42 | } |
||||
43 | |||||
44 | public function setObserver(ObserverInterface $observer): void |
||||
45 | { |
||||
46 | $this->extraPhpDocTagResolver->setObserver($observer); |
||||
47 | } |
||||
48 | |||||
49 | protected function getVertex(ReflectionClass $class): Vertex |
||||
50 | { |
||||
51 | $vertexId = FullyQualifiedStructuralElementName::createClass($class->getName())->toString(); |
||||
52 | if ($this->graph->hasVertex($vertexId)) { |
||||
53 | return $this->graph->getVertex($vertexId); |
||||
54 | } |
||||
55 | |||||
56 | $vertex = $this->graph->createVertex($vertexId); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
57 | $vertex->setAttribute('reflection', $class); |
||||
58 | $vertex->setAttribute(DepsInternal::getTagName(), array_merge( |
||||
59 | $this->extraPhpDocTagResolver->resolveDepsInternalTag($class), |
||||
60 | $this->extraPhpDocTagResolver->resolveCanOnlyUsedByTag($class) |
||||
61 | )); |
||||
62 | $vertex->setAttribute(Internal::getTagName(), $this->extraPhpDocTagResolver->resolveInternalTag($class)); |
||||
63 | |||||
64 | return $vertex; |
||||
65 | } |
||||
66 | |||||
67 | protected function getUnknownClassVertex(string $className): Vertex |
||||
68 | { |
||||
69 | $vertexId = FullyQualifiedStructuralElementName::createClass($className)->toString(); |
||||
70 | if ($this->graph->hasVertex($vertexId)) { |
||||
71 | $vertex = $this->graph->getVertex($vertexId); |
||||
72 | if (!$vertex->getAttribute('reflection') instanceof UnknownReflectionClass) { |
||||
73 | throw new LogicException("{$className} is not UnknownClassReflection"); |
||||
74 | } |
||||
75 | |||||
76 | return $vertex; |
||||
77 | } |
||||
78 | |||||
79 | $vertex = $this->graph->createVertex($vertexId); |
||||
0 ignored issues
–
show
$vertexId of type string is incompatible with the type integer|null expected by parameter $id of Fhaculty\Graph\Graph::createVertex() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
80 | $vertex->setAttribute('reflection', new UnknownReflectionClass($className)); |
||||
81 | $vertex->setAttribute(DepsInternal::getTagName(), []); |
||||
82 | $vertex->setAttribute(Internal::getTagName(), []); |
||||
83 | |||||
84 | return $vertex; |
||||
85 | } |
||||
86 | |||||
87 | protected function addDependencyType(Vertex $depender, Vertex $dependee, DependencyType $additional): void |
||||
88 | { |
||||
89 | if (count($edges = $depender->getEdgesTo($dependee)) === 0) { |
||||
90 | $depender->createEdgeTo($dependee); |
||||
91 | } |
||||
92 | |||||
93 | $edge = $depender->getEdgesTo($dependee)->getEdgeFirst(); |
||||
94 | $types = $edge->getAttribute(DependencyGraph::DEPENDENCY_TYPE_KEY) ?? []; |
||||
95 | |||||
96 | foreach ($types as $type) { |
||||
97 | /** @var DependencyType $type */ |
||||
98 | if ($type->isEqual($additional)) { |
||||
99 | return; |
||||
100 | } |
||||
101 | } |
||||
102 | |||||
103 | $types[] = $additional; |
||||
104 | $edge->setAttribute(DependencyGraph::DEPENDENCY_TYPE_KEY, $types); |
||||
105 | } |
||||
106 | |||||
107 | /** |
||||
108 | * @param ReflectionClass $dependerReflection |
||||
109 | * @param ReflectionClass $dependeeReflection |
||||
110 | */ |
||||
111 | public function addDependency(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection): void |
||||
112 | { |
||||
113 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
114 | $this->addDependencyType( |
||||
115 | $this->getVertex($dependerReflection), |
||||
116 | $this->getVertex($dependeeReflection), |
||||
117 | new SomeDependency() |
||||
118 | ); |
||||
119 | } |
||||
120 | } |
||||
121 | |||||
122 | public function addUnknownDependency(ReflectionClass $dependerReflection, string $dependeeName) |
||||
123 | { |
||||
124 | $this->addDependencyType( |
||||
125 | $this->getVertex($dependerReflection), |
||||
126 | $this->getUnknownClassVertex($dependeeName), |
||||
127 | new SomeDependency() |
||||
128 | ); |
||||
129 | } |
||||
130 | |||||
131 | public function addNew(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $caller = null) |
||||
132 | { |
||||
133 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
134 | $this->addDependencyType( |
||||
135 | $this->getVertex($dependerReflection), |
||||
136 | $this->getVertex($dependeeReflection), |
||||
137 | new NewObject($caller) |
||||
138 | ); |
||||
139 | } |
||||
140 | } |
||||
141 | |||||
142 | public function addMethodCall(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $callee, string $caller = null) |
||||
143 | { |
||||
144 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
145 | $this->addDependencyType( |
||||
146 | $this->getVertex($dependerReflection), |
||||
147 | $this->getVertex($dependeeReflection), |
||||
148 | new MethodCall($callee, $caller) |
||||
149 | ); |
||||
150 | } |
||||
151 | } |
||||
152 | |||||
153 | public function addPropertyFetch(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $propertyName, string $caller = null) |
||||
154 | { |
||||
155 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
156 | $this->addDependencyType( |
||||
157 | $this->getVertex($dependerReflection), |
||||
158 | $this->getVertex($dependeeReflection), |
||||
159 | new PropertyFetch($propertyName, $caller) |
||||
160 | ); |
||||
161 | } |
||||
162 | } |
||||
163 | |||||
164 | public function addConstFetch(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $constantName, string $caller = null) |
||||
165 | { |
||||
166 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
167 | $this->addDependencyType( |
||||
168 | $this->getVertex($dependerReflection), |
||||
169 | $this->getVertex($dependeeReflection), |
||||
170 | new ConstantFetch($constantName, $caller) |
||||
171 | ); |
||||
172 | } |
||||
173 | } |
||||
174 | |||||
175 | public function addExtends(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection) |
||||
176 | { |
||||
177 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
178 | $this->addDependencyType( |
||||
179 | $this->getVertex($dependerReflection), |
||||
180 | $this->getVertex($dependeeReflection), |
||||
181 | new ExtendsClass() |
||||
182 | ); |
||||
183 | } |
||||
184 | } |
||||
185 | |||||
186 | public function addImplements(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection) |
||||
187 | { |
||||
188 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
189 | $this->addDependencyType( |
||||
190 | $this->getVertex($dependerReflection), |
||||
191 | $this->getVertex($dependeeReflection), |
||||
192 | new ImplementsClass() |
||||
193 | ); |
||||
194 | } |
||||
195 | } |
||||
196 | |||||
197 | public function addUseTrait(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection) |
||||
198 | { |
||||
199 | if ($dependerReflection->getName() !== $dependeeReflection->getName()) { |
||||
200 | $this->addDependencyType( |
||||
201 | $this->getVertex($dependerReflection), |
||||
202 | $this->getVertex($dependeeReflection), |
||||
203 | new UseTrait() |
||||
204 | ); |
||||
205 | } |
||||
206 | } |
||||
207 | |||||
208 | public function build(): DependencyGraph |
||||
209 | { |
||||
210 | return new DependencyGraph($this->graph); |
||||
211 | } |
||||
212 | } |
||||
213 |