Path::haveCycle()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 0
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace DependencyAnalyzer\DependencyGraph;
5
6
use DependencyAnalyzer\Exceptions\InvalidEdgeOnPathException;
7
use Fhaculty\Graph\Edge\Directed;
8
9
class Path implements \Countable
10
{
11
    /**
12
     * @var Directed[]
13
     */
14
    private $edges = [];
15
16
    public function __construct(array $edges = [])
17
    {
18
        foreach ($edges as $edge) {
19
            if (!$this->isCanConnectTo($edge)) {
20
                throw new InvalidEdgeOnPathException($edge);
21
            }
22
23
            $this->edges[] = $edge;
24
        }
25
    }
26
27
    protected function isCanConnectTo(Directed $edge): bool
28
    {
29
        if ($last = $this->getLastEdge()) {
30
            return $last->getVertexEnd()->getId() === $edge->getVertexStart()->getId();
31
        }
32
33
        return true;
34
    }
35
36
    public function addEdge(Directed $edge): self
37
    {
38
        if (!$this->isCanConnectTo($edge)) {
39
            throw new InvalidEdgeOnPathException($edge);
40
        }
41
42
        return new self(array_merge($this->edges, [$edge]));
43
    }
44
45
    public function haveCycle(): bool
46
    {
47
        $visitedVertex = [];
48
49
        foreach ($this->edges as $edge) {
50
            $visitedVertex[] = $edge->getVertexStart()->getId();
51
52
            if (in_array($edge->getVertexEnd()->getId(), $visitedVertex)) {
53
                return true;
54
            }
55
        }
56
57
        return false;
58
    }
59
60
    public function isSimpleCycle(): bool
61
    {
62
        if (!$this->haveCycle()) {
63
            return false;
64
        }
65
66
        $visitedVertices = [];
67
        foreach ($this->edges as $edge) {
68
            if (in_array($edge->getVertexStart()->getId(), $visitedVertices)) {
69
                return false;
70
            }
71
            $visitedVertices[] = $edge->getVertexStart()->getId();
72
        }
73
74
        return $this->getFirstEdge()->getVertexStart()->getId() === $this->getLastEdge()->getVertexEnd()->getId();
75
    }
76
77
    public function isEqual(Path $that): bool
78
    {
79
        if ($this->count() === 0 || $that->count() === 0) {
80
            // Path do not have edge is not equal to anything.
81
            return false;
82
        } elseif ($this->count() !== $that->count()) {
83
            return false;
84
        } elseif ($this->haveCycle() !== $that->haveCycle()) {
85
            return false;
86
        } elseif ($this->isSimpleCycle() !== $that->isSimpleCycle()) {
87
            return false;
88
        } elseif ($this->isSimpleCycle() && $that->isSimpleCycle()) {
89
            return empty(array_diff($this->toArray(), $that->toArray())) && empty(array_diff($that->toArray(), $this->toArray()));
90
        } else {
91
            return $this->toArray() === $that->toArray();
92
        }
93
    }
94
95
    protected function getFirstEdge(): ?Directed
96
    {
97
        if ($this->count() === 0) {
98
            return null;
99
        }
100
101
        return $this->edges[0];
102
    }
103
104
    protected function getLastEdge(): ?Directed
105
    {
106
        if ($this->count() === 0) {
107
            return null;
108
        }
109
110
        $edge = end($this->edges);
111
        reset($this->edges);
112
113
        return $edge;
114
    }
115
116
    /**
117
     * @return string[]
118
     */
119
    public function toArray(): array
120
    {
121
        if ($this->count() === 0) {
122
            return [];
123
        }
124
125
        $ids = [$this->edges[0]->getVertexStart()->getId()];
126
        foreach ($this->edges as $edge) {
127
            $ids[] = $edge->getVertexEnd()->getId();
128
        }
129
130
        return $ids;
131
    }
132
133
    public function count(): int
134
    {
135
        return count($this->edges);
136
    }
137
}
138