Passed
Push — master ( da3a15...020c57 )
by Satoshi
02:44
created

DependencyGraph::getDependencyArrows()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace DependencyAnalyzer;
5
6
use DependencyAnalyzer\DependencyGraph\ClassLike;
7
use DependencyAnalyzer\DependencyGraph\DependencyArrow;
8
use DependencyAnalyzer\DependencyGraph\DependencyTypes\Base as DependencyType;
9
use DependencyAnalyzer\DependencyGraph\Path;
10
use DependencyAnalyzer\Exceptions\InvalidEdgeOnDependencyGraphException;
11
use DependencyAnalyzer\DependencyGraph\StructuralElementPatternMatcher;
12
use Fhaculty\Graph\Edge\Directed;
13
use Fhaculty\Graph\Graph;
14
use Fhaculty\Graph\Set\Vertices;
15
use Fhaculty\Graph\Vertex;
16
17
class DependencyGraph implements \Countable
18
{
19
    const DEPENDENCY_TYPE_KEY = 'dependency_types';
20
21
    const TYPE_SOME_DEPENDENCY = 'some_dependency';
22
    const TYPE_NEW = 'new';
23
    const TYPE_METHOD_CALL = 'method_call';
24
    const TYPE_PROPERTY_FETCH = 'property_fetch';
25
    const TYPE_CONSTANT_FETCH = 'constant_fetch';
26
    const TYPE_EXTENDS = 'extends';
27
    const TYPE_IMPLEMENTS = 'implements';
28
    const TYPE_USE_TRAIT = 'use_trait';
29
30
    /**
31
     * @var Graph
32
     */
33
    private $graph;
34
35
    public function __construct(Graph $graph)
36
    {
37
        foreach ($graph->getEdges() as $edge) {
38
            if (!$edge instanceof Directed) {
39
                throw new InvalidEdgeOnDependencyGraphException($edge);
40
            }
41
        }
42
        $this->graph = $graph;
43
    }
44
45
    public function getGraph()
46
    {
47
        return $this->graph;
48
    }
49
50
    /**
51
     * @return ClassLike[]
52
     */
53
    public function getClasses(): array
54
    {
55
        $ret = [];
56
        foreach ($this->graph->getVertices() as $vertex) {
57
            $ret[] = new ClassLike($vertex);
58
        }
59
60
        return $ret;
61
    }
62
63
    /**
64
     * @return DependencyArrow[]
65
     */
66
    public function getDependencyArrows(): array
67
    {
68
        $ret = [];
69
70
        foreach ($this->graph->getEdges() as $edge) {
71
            $ret[] = new DependencyArrow($edge);
72
        }
73
74
        return $ret;
75
    }
76
77
    public function groupByPattern(string $name, StructuralElementPatternMatcher $pattern)
78
    {
79
        $graph = new Graph();
80
        $graph->createVertex($name);
0 ignored issues
show
Bug introduced by
$name 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

80
        $graph->createVertex(/** @scrutinizer ignore-type */ $name);
Loading history...
81
        foreach ($this->getClasses() as $class) {
82
            if (!$pattern->isMatch($class->getName())) {
83
                $graph->createVertex($class->getName());
84
            }
85
        }
86
87
        foreach ($this->getDependencyArrows() as $dependencyArrow) {
88
            $start = $pattern->isMatch($dependencyArrow->getDependerName()) ? $name : $dependencyArrow->getDependerName();
89
            $end = $pattern->isMatch($dependencyArrow->getDependeeName()) ? $name : $dependencyArrow->getDependeeName();
90
91
            if ($start !== $end && !$graph->getVertex($start)->hasEdgeTo($graph->getVertex($end))) {
92
                $graph->getVertex($start)->createEdgeTo($graph->getVertex($end));
93
            }
94
        }
95
96
        return new self($graph);
97
    }
98
99
    public function getConnectedSubGraphsStartFrom(Vertex $vertex)
100
    {
101
        $vertices = $this->collectConnectedVertices($vertex);
102
        return new self($this->graph->createGraphCloneVertices($vertices));
103
    }
104
105
    protected function collectConnectedVertices(Vertex $start)
106
    {
107
        $visited = [];
108
109
        /**
110
         * @var Vertex[] $queue
111
         */
112
        $queue = [$start];
113
        // Breadth first search
114
        do {
115
            $target = array_shift($queue);
116
            $visited[$target->getId()]= $target;
117
118
            foreach ($target->getVerticesEdgeTo()->getMap() as $id => $vertexTo) {
119
                if (!isset($visited[$id])) {
120
                    $queue[] = $vertexTo;
121
                }
122
            }
123
        } while ($queue);
124
125
        return new Vertices(array_values($visited));
126
    }
127
128
    public function walkOnPath(callable $carry)
129
    {
130
        foreach ($this->graph->getEdges() as $edge) {
131
            $this->walkThroughEdge($edge, new Path(), $carry);
132
        }
133
    }
134
135
    protected function walkThroughEdge(Directed $edge, Path $path, callable $carry)
136
    {
137
        $path = $path->addEdge($edge);
138
        $carry($path);
139
140
        if (!$path->haveCycle()) {
141
            $edgesOut = $edge->getVertexEnd()->getEdgesOut();
142
            foreach ($edgesOut as $edgeOut) {
143
                $this->walkThroughEdge($edgeOut, $path, $carry);
144
            }
145
        }
146
    }
147
148
    public function toArray()
149
    {
150
        $ret = [];
151
152
        foreach ($this->graph->getVertices() as $vertex) {
153
            $ret[$vertex->getId()] = [];
154
155
            foreach ($vertex->getEdgesOut() as $edge) {
156
                /** @var Directed $edge */
157
                $types = $edge->getAttribute(DependencyGraph::DEPENDENCY_TYPE_KEY) ?? [];
158
159
                $ret[$vertex->getId()][$edge->getVertexEnd()->getId()] = array_map(function (DependencyType $type) {
160
                    return $type->toString();
161
                }, $types);
162
            }
163
        }
164
165
        return $ret;
166
    }
167
168
    public function count()
169
    {
170
        return count($this->graph->getVertices());
171
    }
172
}
173