Passed
Push — master ( 65484c...fedbc6 )
by Satoshi
02:08
created

DependencyGraphBuilder::setObserver()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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\DependencyGraphBuilder\ExtraPhpDocTagResolver;
16
use DependencyAnalyzer\DependencyGraphBuilder\ObserverInterface;
17
use DependencyAnalyzer\DependencyGraphBuilder\UnknownReflectionClass;
18
use DependencyAnalyzer\Exceptions\LogicException;
19
use Fhaculty\Graph\Graph;
20
use Fhaculty\Graph\Vertex;
21
use ReflectionClass;
22
23
class DependencyGraphBuilder
24
{
25
    /**
26
     * @var Graph
27
     */
28
    protected $graph;
29
30
    /**
31
     * @var ExtraPhpDocTagResolver
32
     */
33
    protected $extraPhpDocTagResolver;
34
35
    public function __construct(ExtraPhpDocTagResolver $extraPhpDocTagResolver)
36
    {
37
        $this->graph = new Graph;
38
        $this->extraPhpDocTagResolver = $extraPhpDocTagResolver;
39
    }
40
41
    public function setObserver(ObserverInterface $observer): void
42
    {
43
        $this->extraPhpDocTagResolver->setObserver($observer);
44
    }
45
46
    protected function getVertex(ReflectionClass $class): Vertex
47
    {
48
        if ($this->graph->hasVertex($class->getName())) {
49
            return $this->graph->getVertex($class->getName());
50
        }
51
52
        $vertex = $this->graph->createVertex($class->getName());
0 ignored issues
show
Bug introduced by
$class->getName() 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 ignore-type  annotation

52
        $vertex = $this->graph->createVertex(/** @scrutinizer ignore-type */ $class->getName());
Loading history...
53
        $vertex->setAttribute('reflection', $class);
54
        $vertex->setAttribute(ExtraPhpDocTagResolver::ONLY_USED_BY_TAGS, $this->extraPhpDocTagResolver->resolveCanOnlyUsedByTag($class));
55
        $vertex->setAttribute(ExtraPhpDocTagResolver::DEPS_INTERNAL, $this->extraPhpDocTagResolver->resolveDepsInternalTag($class));
56
57
        return $vertex;
58
    }
59
60
    protected function getUnknownClassVertex(string $className): Vertex
61
    {
62
        if ($this->graph->hasVertex($className)) {
63
            $vertex = $this->graph->getVertex($className);
64
            if (!$vertex->getAttribute('reflection') instanceof UnknownReflectionClass) {
65
                throw new LogicException("{$className} is not UnknownClassReflection");
66
            }
67
68
            return $vertex;
69
        }
70
71
        $vertex = $this->graph->createVertex($className);
0 ignored issues
show
Bug introduced by
$className 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 ignore-type  annotation

71
        $vertex = $this->graph->createVertex(/** @scrutinizer ignore-type */ $className);
Loading history...
72
        $vertex->setAttribute('reflection', new UnknownReflectionClass($className));
73
        $vertex->setAttribute(ExtraPhpDocTagResolver::ONLY_USED_BY_TAGS, []);
74
        $vertex->setAttribute(ExtraPhpDocTagResolver::DEPS_INTERNAL, []);
75
76
        return $vertex;
77
    }
78
79
    protected function addDependencyType(Vertex $depender, Vertex $dependee, DependencyType $additional): void
80
    {
81
        if (count($edges = $depender->getEdgesTo($dependee)) === 0) {
82
            $depender->createEdgeTo($dependee);
83
        }
84
85
        $edge = $depender->getEdgesTo($dependee)->getEdgeFirst();
86
        $types = $edge->getAttribute(DependencyGraph::DEPENDENCY_TYPE_KEY) ?? [];
87
88
        foreach ($types as $type) {
89
            /** @var DependencyType $type */
90
            if ($type->isEqual($additional)) {
91
                return;
92
            }
93
        }
94
95
        $types[] = $additional;
96
        $edge->setAttribute(DependencyGraph::DEPENDENCY_TYPE_KEY, $types);
97
    }
98
99
    /**
100
     * @param ReflectionClass $dependerReflection
101
     * @param ReflectionClass $dependeeReflection
102
     */
103
    public function addDependency(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection): void
104
    {
105
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
106
            $this->addDependencyType(
107
                $this->getVertex($dependerReflection),
108
                $this->getVertex($dependeeReflection),
109
                new SomeDependency()
110
            );
111
        }
112
    }
113
114
    public function addUnknownDependency(ReflectionClass $dependerReflection, string $dependeeName)
115
    {
116
        $this->addDependencyType(
117
            $this->getVertex($dependerReflection),
118
            $this->getUnknownClassVertex($dependeeName),
119
            new SomeDependency()
120
        );
121
    }
122
123
    public function addNew(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $caller = null)
124
    {
125
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
126
            $this->addDependencyType(
127
                $this->getVertex($dependerReflection),
128
                $this->getVertex($dependeeReflection),
129
                new NewObject($caller)
130
            );
131
        }
132
    }
133
134
    public function addMethodCall(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $callee, string $caller = null)
135
    {
136
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
137
            $this->addDependencyType(
138
                $this->getVertex($dependerReflection),
139
                $this->getVertex($dependeeReflection),
140
                new MethodCall($callee, $caller)
141
            );
142
        }
143
    }
144
145
    public function addPropertyFetch(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $propertyName, string $caller = null)
146
    {
147
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
148
            $this->addDependencyType(
149
                $this->getVertex($dependerReflection),
150
                $this->getVertex($dependeeReflection),
151
                new PropertyFetch($propertyName, $caller)
152
            );
153
        }
154
    }
155
156
    public function addConstFetch(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection, string $constantName, string $caller = null)
157
    {
158
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
159
            $this->addDependencyType(
160
                $this->getVertex($dependerReflection),
161
                $this->getVertex($dependeeReflection),
162
                new ConstantFetch($constantName, $caller)
163
            );
164
        }
165
    }
166
167
    public function addExtends(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection)
168
    {
169
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
170
            $this->addDependencyType(
171
                $this->getVertex($dependerReflection),
172
                $this->getVertex($dependeeReflection),
173
                new ExtendsClass()
174
            );
175
        }
176
    }
177
178
    public function addImplements(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection)
179
    {
180
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
181
            $this->addDependencyType(
182
                $this->getVertex($dependerReflection),
183
                $this->getVertex($dependeeReflection),
184
                new ImplementsClass()
185
            );
186
        }
187
    }
188
189
    public function addUseTrait(ReflectionClass $dependerReflection, ReflectionClass $dependeeReflection)
190
    {
191
        if ($dependerReflection->getName() !== $dependeeReflection->getName()) {
192
            $this->addDependencyType(
193
                $this->getVertex($dependerReflection),
194
                $this->getVertex($dependeeReflection),
195
                new UseTrait()
196
            );
197
        }
198
    }
199
200
    public function build(): DependencyGraph
201
    {
202
        return new DependencyGraph($this->graph);
203
    }
204
}
205